

這是 AWS CDK v2 開發人員指南。較舊的 CDK v1 已於 2022 年 6 月 1 日進入維護，並於 2023 年 6 月 1 日結束支援。

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# AWS CDK 建構
<a name="constructs"></a>

建構是 AWS 雲端開發套件 (AWS CDK) 應用程式的基本建置區塊。建構是應用程式中代表一或多個 AWS CloudFormation 資源及其組態的元件。您可以透過匯入和設定建構模組，逐個建置您的應用程式。

## 匯入和使用建構
<a name="constructs-import"></a>

建構是您從[AWS 建構程式庫](libraries.md#libraries-construct)匯入 CDK 應用程式的類別。您也可以建立和分發自己的建構，或使用第三方開發人員建立的建構。

建構是建構程式設計模型 (CPM) 的一部分。它們可用於其他工具，例如 CDK for Terraform(CDKtf)、CDK for Kubernetes(CDK8s) 和 Projen。

許多第三方也發佈了與 AWS CDK 相容的建構。請造訪 [Construct Hub](https://constructs.dev/search?q=&cdk=aws-cdk&cdkver=2&offset=0) 探索 AWS CDK 建構合作夥伴生態系統。

## 建構層級
<a name="constructs-lib-levels"></a>

建構程式庫中的 AWS 建構分為三個層級。每個層級提供更高層級的抽象。抽象程度越高，設定越容易，需要的專業知識就越少。抽象度越低，可用的自訂越多，需要更多專業知識。<a name="constructs-lib-levels-one"></a>

 **第 1 級 (L1) 建構**   
L1 建構模組也稱為 *CFN 資源*，是最低層級的建構模組，不提供抽象。每個 L1 建構直接映射到單一 AWS CloudFormation 資源。使用 L1 建構時，您可以匯入代表特定 AWS CloudFormation 資源的建構。然後，您可以在建構執行個體中定義資源的屬性。  
當您熟悉 AWS CloudFormation 且需要完全控制您的 AWS 資源屬性時，L1 建構很適合使用。  
在 AWS 建構程式庫中，L1 建構會以 開頭命名`Cfn`，後面接著其所代表之 AWS CloudFormation 資源的識別符。例如， [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.CfnBucket.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.CfnBucket.html) 建構是代表 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.Bucket.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.Bucket.html) AWS CloudFormation 資源的 L1 建構。  
L1 建構是從 [AWS CloudFormation 資源規格](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-resource-specification.html)產生。如果資源存在於 AWS CloudFormation 中，則會在 AWS CDK 中做為 L1 建構模組使用。建構 AWS 程式庫中的新資源或屬性可能需要一週的時間才能使用。如需詳細資訊，請參閱《* AWS CloudFormation 使用者指南*》中的[AWS 資源和屬性類型參考](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html)。<a name="constructs-lib-levels-two"></a>

 **第 2 級 (L2) 建構**   
L2 建構體也稱為*精選*建構體，由 CDK 團隊精心開發，通常是最廣泛使用的建構體類型。L2 建構直接映射至 single AWS CloudFormation 資源，類似於 L1 建構。相較於 L1 建構，L2 建構透過直覺式意圖型 API 提供更高層級的抽象。L2 建構包含合理的預設屬性組態、最佳實務安全政策，並為您產生許多樣板程式碼和黏附邏輯。  
L2 建構也為大多數資源提供協助程式方法，讓定義屬性、許可、以事件為基礎的資源間互動等更加簡單快速。其中許多功能也可以做為名為 [Mixins](mixins.md) 的獨立建置區塊使用，可使用 `.with()`方法套用至 L1 和 L2 建構。  
[https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.Bucket.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.Bucket.html) 類別是 Amazon Simple Storage Service (Amazon S3) 儲存貯體資源的 L2 建構範例。  
 AWS 建構程式庫包含 L2 建構，指定為穩定且已準備好供生產使用。對於開發中的 L2 建構，它們被指定為實驗性，並在單獨的模組中提供。<a name="constructs-lib-levels-three"></a>

 **第 3 級 (L3) 建構**   
L3 建構體也稱為*模式*，是抽象的最高層級。每個 L3 建構可以包含資源的集合，這些資源設定為一起運作，以完成應用程式中的特定任務或服務。L3 建構用於為應用程式中的特定使用案例建立整個 AWS 架構。  
為了提供完整的系統設計或更大型系統的實質部分，L3 建構提供有意見的預設屬性組態。它們是以解決問題和提供解決方案的特定方法為基礎。透過 L3 建構，您可以使用最少的輸入量和程式碼，快速建立和設定多個資源。  
[https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs_patterns.ApplicationLoadBalancedFargateService.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs_patterns.ApplicationLoadBalancedFargateService.html) 類別是 L3 建構範例，代表在 Amazon Elastic Container Service (Amazon ECS) 叢集上執行並由應用程式負載平衡器前的 AWS Fargate 服務。  
與 L2 建構類似，準備好供生產使用的 L3 建構包含在 AWS 建構程式庫中。開發中項目會以不同的模組提供。

## 定義建構
<a name="constructs-define"></a>

### 合成
<a name="constructs-composition"></a>

 *合成*是透過建構定義更高層級抽象的關鍵模式。高階建構模組可由任意數量的低階建構模組組成。從由下而上的觀點來看，您可以使用 建構來組織您要部署的個別 AWS 資源。您可以使用任何方便用於您用途的抽象內容，並根據需要擁有任意數量的關卡。

透過合成，您可以定義可重複使用的元件，並與任何其他程式碼共用它們。例如，團隊可以定義結構，以實作 Amazon DynamoDB 資料表的公司最佳實務，包括備份、全域複寫、自動擴展和監控。團隊可以在內部與其他團隊或公開共用建構。

團隊可以使用與任何其他程式庫套件類似的建構。當程式庫更新時，開發人員可以存取新版本的改進和錯誤修正，類似於任何其他程式庫。

### 初始化
<a name="constructs-init"></a>

建構模組在延伸 [https://docs.aws.amazon.com/cdk/api/v2/docs/constructs.Construct.html](https://docs.aws.amazon.com/cdk/api/v2/docs/constructs.Construct.html) 基本類別的類別中實作。您可以透過執行個體化 類別來定義建構。所有建構模組在初始化時都採用以下三個參數：
+  **範圍** – 建構的父系或擁有者。這可以是堆疊或其他建構。範圍會決定建構樹狀結構中[的位置](apps.md#apps-tree)。您通常應該傳遞 `this`(`self`以 Python 為單位），代表範圍的目前物件。
+  **id** – 在範圍內必須是唯一的[識別符](identifiers.md)。識別符可做為建構中定義之所有項目的命名空間。它用於產生唯一識別符，例如[資源名稱](resources.md#resources-physical-names)和 AWS CloudFormation 邏輯 IDs。

  識別符在範圍內只需要是唯一的。這可讓您執行個體化和重複使用建構，而不必擔心其可能包含的建構和識別符，並啟用將建構編寫為更高層級的抽象。此外，範圍可讓您一次參考建構的群組。範例包括[標記](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Tag.html)，或指定要部署建構的位置。
+  **props** – 一組屬性或關鍵字引數，取決於定義建構結構初始組態的語言。較高層級的建構提供更多預設值，如果所有 prop 元素都是選用的，您可以完全省略 props 參數。

### Configuration
<a name="constructs-config"></a>

大多數建構接受 `props`作為其第三個引數 （或在 Python 中為關鍵字引數），這是定義建構組態的名稱/值集合。下列範例會定義啟用 AWS Key Management Service (AWS KMS) 加密和靜態網站託管的儲存貯體。由於未明確指定加密金鑰，因此建構會定義新的 `Bucket` `kms.Key`，並將其與儲存貯體建立關聯。

**Example**  

```
new s3.Bucket(this, 'MyEncryptedBucket', {
  encryption: s3.BucketEncryption.KMS,
  websiteIndexDocument: 'index.html'
});
```

```
new s3.Bucket(this, 'MyEncryptedBucket', {
  encryption: s3.BucketEncryption.KMS,
  websiteIndexDocument: 'index.html'
});
```

```
s3.Bucket(self, "MyEncryptedBucket", encryption=s3.BucketEncryption.KMS,
    website_index_document="index.html")
```

```
Bucket.Builder.create(this, "MyEncryptedBucket")
        .encryption(BucketEncryption.KMS_MANAGED)
        .websiteIndexDocument("index.html").build();
```

```
new Bucket(this, "MyEncryptedBucket", new BucketProps
{
    Encryption = BucketEncryption.KMS_MANAGED,
    WebsiteIndexDocument = "index.html"
});
```

```
	awss3.NewBucket(stack, jsii.String("MyEncryptedBucket"), &awss3.BucketProps{
		Encryption: awss3.BucketEncryption_KMS,
		WebsiteIndexDocument: jsii.String("index.html"),
	})
```

### 與建構模組互動
<a name="constructs-interact"></a>

建構是擴展基礎[建構](https://docs.aws.amazon.com/cdk/api/v2/docs/constructs.Construct.html)類別的類別。在您執行個體化建構模組後，建構物件會公開一組方法和屬性，讓您與建構模組互動，並將其做為系統其他部分的參考。

 AWS CDK 架構不會對建構APIs 施加任何限制。作者可以定義他們想要的任何 API。不過， AWS AWS 建構程式庫隨附的建構模組，例如 `s3.Bucket`，遵循準則和常見模式。這在所有 AWS 資源中提供一致的體驗。

大多數 AWS 建構有一組[授予](permissions.md#permissions-grants)方法，您可以用來將建構上的 AWS Identity and Access Management (IAM) 許可授予委託人。下列範例授予 IAM 群組從 Amazon S3 儲存貯體 讀取的`data-science`許可`raw-data`。

**Example**  

```
const rawData = new s3.Bucket(this, 'raw-data');
const dataScience = new iam.Group(this, 'data-science');
rawData.grants.read(dataScience);
```

```
const rawData = new s3.Bucket(this, 'raw-data');
const dataScience = new iam.Group(this, 'data-science');
rawData.grants.read(dataScience);
```

```
raw_data = s3.Bucket(self, 'raw-data')
data_science = iam.Group(self, 'data-science')
raw_data.grants.read(data_science)
```

```
Bucket rawData = new Bucket(this, "raw-data");
Group dataScience = new Group(this, "data-science");
rawData.getGrants().read(dataScience);
```

```
var rawData = new Bucket(this, "raw-data");
var dataScience = new Group(this, "data-science");
rawData.Grants.Read(dataScience);
```

```
	rawData := awss3.NewBucket(stack, jsii.String("raw-data"), nil)
	dataScience := awsiam.NewGroup(stack, jsii.String("data-science"), nil)
	rawData.Grants().Read(dataScience, nil)
```

另一個常見模式是供 AWS 建構從其他位置提供的資料設定其中一個資源的屬性。屬性可以包含 Amazon Resource Name (ARNs)、名稱或 URLs。

下列程式碼定義 AWS Lambda 函數，並透過 環境變數中的佇列 URL 將其與 Amazon Simple Queue Service (Amazon SQS) 佇列建立關聯。

**Example**  

```
const jobsQueue = new sqs.Queue(this, 'jobs');
const createJobLambda = new lambda.Function(this, 'create-job', {
  runtime: lambda.Runtime.NODEJS_18_X,
  handler: 'index.handler',
  code: lambda.Code.fromAsset('./create-job-lambda-code'),
  environment: {
    QUEUE_URL: jobsQueue.queueUrl
  }
});
```

```
const jobsQueue = new sqs.Queue(this, 'jobs');
const createJobLambda = new lambda.Function(this, 'create-job', {
  runtime: lambda.Runtime.NODEJS_18_X,
  handler: 'index.handler',
  code: lambda.Code.fromAsset('./create-job-lambda-code'),
  environment: {
    QUEUE_URL: jobsQueue.queueUrl
  }
});
```

```
jobs_queue = sqs.Queue(self, "jobs")
create_job_lambda = lambda_.Function(self, "create-job",
    runtime=lambda_.Runtime.NODEJS_18_X,
    handler="index.handler",
    code=lambda_.Code.from_asset("./create-job-lambda-code"),
    environment=dict(
        QUEUE_URL=jobs_queue.queue_url
    )
)
```

```
final Queue jobsQueue = new Queue(this, "jobs");
Function createJobLambda = Function.Builder.create(this, "create-job")
                .handler("index.handler")
                .code(Code.fromAsset("./create-job-lambda-code"))
                .environment(java.util.Map.of(   // Map.of is Java 9 or later
                    "QUEUE_URL", jobsQueue.getQueueUrl()))
                .build();
```

```
var jobsQueue = new Queue(this, "jobs");
var createJobLambda = new Function(this, "create-job", new FunctionProps
{
    Runtime = Runtime.NODEJS_18_X,
    Handler = "index.handler",
    Code = Code.FromAsset(@".\create-job-lambda-code"),
    Environment = new Dictionary<string, string>
    {
        ["QUEUE_URL"] = jobsQueue.QueueUrl
    }
});
```

```
	createJobLambda := awslambda.NewFunction(stack, jsii.String("create-job"), &awslambda.FunctionProps{
		Runtime: awslambda.Runtime_NODEJS_18_X(),
		Handler: jsii.String("index.handler"),
		Code:    awslambda.Code_FromAsset(jsii.String(".\\create-job-lambda-code"), nil),
		Environment: &map[string]*string{
			"QUEUE_URL": jsii.String(*jobsQueue.QueueUrl()),
		},
	})
```

如需 AWS 建構程式庫中最常見 API 模式的相關資訊，請參閱 [資源和 AWS CDK](resources.md)。

### 使用 Mixins 新增功能
<a name="constructs-mixins"></a>

混合是可編寫的功能，您可以使用 `.with()`方法套用至任何建構。混合可讓您將功能新增至 L1 和 L2 建構，而無需使用不同的建構或寫入低階程式碼。

例如，您可以在 Amazon S3 儲存貯體上啟用版本控制和封鎖公開存取，無論是 L1 `CfnBucket`還是 L2`Bucket`：

**Example**  

```
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';

// Apply mixins to an L1 construct
new s3.CfnBucket(this, 'MyBucket')
  .with(new s3.mixins.BucketVersioning())
  .with(new s3.mixins.BucketBlockPublicAccess());

// Apply mixins to an L2 construct
new s3.Bucket(this, 'MyL2Bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY })
  .with(new s3.mixins.BucketAutoDeleteObjects());
```

```
const cdk = require('aws-cdk-lib');
const s3 = require('aws-cdk-lib/aws-s3');

// Apply mixins to an L1 construct
new s3.CfnBucket(this, 'MyBucket')
  .with(new s3.mixins.BucketVersioning())
  .with(new s3.mixins.BucketBlockPublicAccess());

// Apply mixins to an L2 construct
new s3.Bucket(this, 'MyL2Bucket', { removalPolicy: cdk.RemovalPolicy.DESTROY })
  .with(new s3.mixins.BucketAutoDeleteObjects());
```

```
import aws_cdk as cdk
import aws_cdk.aws_s3 as s3

# Apply mixins to an L1 construct
s3.CfnBucket(self, "MyBucket") \
    .with_(s3.mixins.BucketVersioning()) \
    .with_(s3.mixins.BucketBlockPublicAccess())

# Apply mixins to an L2 construct
s3.Bucket(self, "MyL2Bucket", removal_policy=cdk.RemovalPolicy.DESTROY) \
    .with_(s3.mixins.BucketAutoDeleteObjects())
```

```
import software.amazon.awscdk.*;
import software.amazon.awscdk.services.s3.*;

// Apply mixins to an L1 construct
CfnBucket bucket = new CfnBucket(this, "MyBucket");
bucket.with(new BucketVersioning());
bucket.with(new BucketBlockPublicAccess());

// Apply mixins to an L2 construct
Bucket l2Bucket = Bucket.Builder.create(this, "MyL2Bucket")
        .removalPolicy(RemovalPolicy.DESTROY)
        .build();
l2Bucket.with(new BucketAutoDeleteObjects());
```

```
using Amazon.CDK;
using Amazon.CDK.AWS.S3;

// Apply mixins to an L1 construct
var bucket = new CfnBucket(this, "MyBucket");
bucket.With(new BucketVersioning());
bucket.With(new BucketBlockPublicAccess());

// Apply mixins to an L2 construct
var l2Bucket = new Bucket(this, "MyL2Bucket", new BucketProps
{
    RemovalPolicy = RemovalPolicy.DESTROY
});
l2Bucket.With(new BucketAutoDeleteObjects());
```

```
bucket := awss3.NewCfnBucket(stack, jsii.String("MyBucket"), nil)
bucket.With(awss3.NewBucketVersioning())
bucket.With(awss3.NewBucketBlockPublicAccess())

l2Bucket := awss3.NewBucket(stack, jsii.String("MyL2Bucket"), &awss3.BucketProps{
    RemovalPolicy: awscdk.RemovalPolicy_DESTROY,
})
l2Bucket.With(awss3.NewBucketAutoDeleteObjects())
```

可透過每個服務模組的`mixins`命名空間 （例如，`s3.mixins`) 使用混合。每個混音都以特定資源類型為目標，並以該資源命名。當您將混音套用至 L2 建構時，它會自動套用至基礎 L1 資源。

如需 Mixins 的詳細資訊，請參閱 [Mixins](mixins.md)。

### 應用程式和堆疊建構
<a name="constructs-apps-stacks"></a>

 AWS 建構程式庫中的 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.App.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.App.html)和 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stack.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stack.html)類別是唯一的建構。與其他建構相比，它們不會自行設定 AWS 資源。反之，它們會用來為您的其他建構提供內容。代表 AWS 資源的所有建構必須直接或間接在`Stack`建構的範圍內定義。 `Stack` 建構是在`App`建構的範圍內定義。

若要進一步了解 CDK 應用程式，請參閱 [AWS CDK 應用程式](apps.md)。若要進一步了解 CDK 堆疊，請參閱 [AWS CDK 堆疊簡介](stacks.md)。

下列範例定義具有單一堆疊的應用程式。在堆疊中，L2 建構用於設定 Amazon S3 儲存貯體資源。

**Example**  

```
import { App, Stack, StackProps } from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';

class HelloCdkStack extends Stack {
  constructor(scope: App, id: string, props?: StackProps) {
    super(scope, id, props);

    new s3.Bucket(this, 'MyFirstBucket', {
      versioned: true
    });
  }
}

const app = new App();
new HelloCdkStack(app, "HelloCdkStack");
```

```
const { App , Stack } = require('aws-cdk-lib');
const s3 = require('aws-cdk-lib/aws-s3');

class HelloCdkStack extends Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    new s3.Bucket(this, 'MyFirstBucket', {
      versioned: true
    });
  }
}

const app = new App();
new HelloCdkStack(app, "HelloCdkStack");
```

```
from aws_cdk import App, Stack
import aws_cdk.aws_s3 as s3
from constructs import Construct

class HelloCdkStack(Stack):

    def __init__(self, scope: Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        s3.Bucket(self, "MyFirstBucket", versioned=True)

app = App()
HelloCdkStack(app, "HelloCdkStack")
```
`HelloCdkStack.java` 檔案中定義的堆疊：  

```
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.s3.*;

public class HelloCdkStack extends Stack {
    public HelloCdkStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public HelloCdkStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        Bucket.Builder.create(this, "MyFirstBucket")
            .versioned(true).build();
    }
}
```
`HelloCdkApp.java` 檔案中定義的應用程式：  

```
import software.amazon.awscdk.App;
import software.amazon.awscdk.StackProps;

public class HelloCdkApp {
    public static void main(final String[] args) {
        App app = new App();

        new HelloCdkStack(app, "HelloCdkStack", StackProps.builder()
                .build());

        app.synth();
    }
}
```

```
using Amazon.CDK;
using Amazon.CDK.AWS.S3;

namespace HelloCdkApp
{
    internal static class Program
    {
        public static void Main(string[] args)
        {
            var app = new App();
            new HelloCdkStack(app, "HelloCdkStack");
            app.Synth();
        }
    }

    public class HelloCdkStack : Stack
    {
        public HelloCdkStack(Construct scope, string id, IStackProps props=null) : base(scope, id, props)
        {
            new Bucket(this, "MyFirstBucket", new BucketProps { Versioned = true });
        }
    }
}
```

```
func NewHelloCdkStack(scope constructs.Construct, id string, props *HelloCdkStackProps) awscdk.Stack {
	var sprops awscdk.StackProps
	if props != nil {
		sprops = props.StackProps
	}
	stack := awscdk.NewStack(scope, &id, &sprops)

	awss3.NewBucket(stack, jsii.String("MyFirstBucket"), &awss3.BucketProps{
		Versioned: jsii.Bool(true),
	})

	return stack
}
```

## 使用建構
<a name="constructs-work"></a>

### 使用 L1 建構
<a name="constructs-l1-using"></a>

L1 建構直接映射至 individual AWS CloudFormation 資源。您必須提供資源所需的組態。

在此範例中，我們使用 `CfnBucket` L1 建構模組建立`bucket`物件：

**Example**  

```
const bucket = new s3.CfnBucket(this, "amzn-s3-demo-bucket", {
  bucketName: "amzn-s3-demo-bucket"
});
```

```
const bucket = new s3.CfnBucket(this, "amzn-s3-demo-bucket", {
  bucketName: "amzn-s3-demo-bucket"
});
```

```
bucket = s3.CfnBucket(self, "amzn-s3-demo-bucket", bucket_name="amzn-s3-demo-bucket")
```

```
CfnBucket bucket = new CfnBucket.Builder().bucketName("amzn-s3-demo-bucket").build();
```

```
var bucket = new CfnBucket(this, "amzn-s3-demo-bucket", new CfnBucketProps
{
    BucketName= "amzn-s3-demo-bucket"
});
```

```
	awss3.NewCfnBucket(stack, jsii.String("amzn-s3-demo-bucket"), &awss3.CfnBucketProps{
		BucketName: jsii.String("amzn-s3-demo-bucket"),
	})
```

非簡單布林值、字串、數字或容器的建構屬性會以支援的語言進行不同的處理。

**Example**  

```
const bucket = new s3.CfnBucket(this, "amzn-s3-demo-bucket", {
  bucketName: "amzn-s3-demo-bucket",
  corsConfiguration: {
    corsRules: [{
          allowedOrigins: ["*"],
          allowedMethods: ["GET"]
    }]
  }
});
```

```
const bucket = new s3.CfnBucket(this, "amzn-s3-demo-bucket", {
  bucketName: "amzn-s3-demo-bucket",
  corsConfiguration: {
    corsRules: [{
          allowedOrigins: ["*"],
          allowedMethods: ["GET"]
    }]
  }
});
```
在 Python 中，這些屬性由定義為 L1 建構的內部類別的類型表示。例如， `cors_configuration`的選用屬性`CfnBucket`需要 類型的包裝函式`CfnBucket.CorsConfigurationProperty`。在這裡，我們在`CfnBucket`執行個體`cors_configuration`上定義 。  

```
bucket = CfnBucket(self, "amzn-s3-demo-bucket", bucket_name="amzn-s3-demo-bucket",
    cors_configuration=CfnBucket.CorsConfigurationProperty(
        cors_rules=[CfnBucket.CorsRuleProperty(
            allowed_origins=["*"],
            allowed_methods=["GET"]
        )]
    )
)
```
在 Java 中，這些屬性由定義為 L1 建構的內部類別的類型表示。例如， `corsConfiguration`的選用屬性`CfnBucket`需要 類型的包裝函式`CfnBucket.CorsConfigurationProperty`。在這裡，我們在`CfnBucket`執行個體`corsConfiguration`上定義 。  

```
CfnBucket bucket = CfnBucket.Builder.create(this, "amzn-s3-demo-bucket")
                        .bucketName("amzn-s3-demo-bucket")
                        .corsConfiguration(new CfnBucket.CorsConfigurationProperty.Builder()
                            .corsRules(Arrays.asList(new CfnBucket.CorsRuleProperty.Builder()
                                .allowedOrigins(Arrays.asList("*"))
                                .allowedMethods(Arrays.asList("GET"))
                                .build()))
                            .build())
                        .build();
```
在 C\$1 中，這些屬性由定義為 L1 建構的內部類別的類型表示。例如， `CorsConfiguration`的選用屬性`CfnBucket`需要 類型的包裝函式`CfnBucket.CorsConfigurationProperty`。在這裡，我們在`CfnBucket`執行個體`CorsConfiguration`上定義 。  

```
var bucket = new CfnBucket(this, "amzn-s3-demo-bucket", new CfnBucketProps
{
    BucketName = "amzn-s3-demo-bucket",
    CorsConfiguration = new CfnBucket.CorsConfigurationProperty
    {
        CorsRules = new object[] {
            new CfnBucket.CorsRuleProperty
            {
                AllowedOrigins = new string[] { "*" },
                AllowedMethods = new string[] { "GET" },
            }
        }
    }
});
```
在 Go 中，這些類型會使用 L1 建構的名稱、底線和屬性名稱來命名。例如， `CorsConfiguration`的選用屬性`CfnBucket`需要 類型的包裝函式`CfnBucket_CorsConfigurationProperty`。在這裡，我們在`CfnBucket`執行個體`CorsConfiguration`上定義 。  

```
	awss3.NewCfnBucket(stack, jsii.String("amzn-s3-demo-bucket"), &awss3.CfnBucketProps{
		BucketName: jsii.String("amzn-s3-demo-bucket"),
		CorsConfiguration: &awss3.CfnBucket_CorsConfigurationProperty{
			CorsRules: []awss3.CorsRule{
				awss3.CorsRule{
					AllowedOrigins: jsii.Strings("*"),
					AllowedMethods: &[]awss3.HttpMethods{"GET"},
				},
			},
		},
	})
```

**重要**  
您無法搭配 L1 建構使用 L2 屬性類型，反之亦然。 L1 使用 L1 建構時，請務必使用您所使用的 L1 建構所定義的類型。請勿使用來自其他 L1 建構的類型 （有些可能具有相同的名稱，但不是相同的類型）。  
我們的一些特定語言 API 參考目前在 L1 屬性類型的路徑中存在錯誤，或者完全不記錄這些類別。我們希望盡快修正此問題。同時，請記住，這類類型一律是與其搭配使用的 L1 建構的內部類別。

#### 參考其他建構中的資源
<a name="constructs-resource-references"></a>

設定參考其他 AWS 資源的建構屬性時，您有兩個同等選項：
+  **字串參考**：傳遞明確的字串值，例如 ARNs、名稱或其他資源識別符
+  **物件參考**：直接傳遞建構物件。這可避免必須判斷屬性預期的識別符類型，CDK 會為您處理。

##### 使用字串參考
<a name="_using_string_references"></a>

您可以隨時傳遞明確的字串值，例如 ARNs、名稱或其他資源識別符。此方法適用於所有屬性，而複雜物件內的巢狀屬性則需要此方法。

下列範例使用 L1 建構 (`CfnFunction`) 建立 Lambda 函數，並使用 L2 建構 () 定義角色`Role`。角色的 ARN 會傳遞至 `role` 屬性：

**Example**  

```
const role = new iam.Role(this, 'MyRole', {
  assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
  managedPolicies: [
    iam.ManagedPolicy.fromAwsManagedPolicyName(
      'service-role/AWSLambdaBasicExecutionRole'
    ),
  ],
});

const myFunction = new lambda.CfnFunction(this, 'HelloWorldFunction', {
  runtime: 'nodejs24.x',
  role: role.roleArn, // Pass the ARN string explicitly
  handler: 'index.handler',
  code: {
    zipFile: `
    exports.handler = async function(event) {
      return {
        statusCode: 200,
        body: JSON.stringify('Hello World!'),
      };
    };
  `}
});
```

```
const role = new iam.Role(this, 'MyRole', {
  assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
  managedPolicies: [
    iam.ManagedPolicy.fromAwsManagedPolicyName(
      'service-role/AWSLambdaBasicExecutionRole'
    )
  ]
});

const myFunction = new lambda.CfnFunction(this, "HelloWorldFunction", {
  runtime: 'nodejs24.x',
  role: role.roleArn, // Pass the ARN string explicitly
  handler: 'index.handler',
  code: {
    zipFile: `
    exports.handler = async function(event) {
      return {
        statusCode: 200,
        body: JSON.stringify('Hello World!'),
      };
    };
  `}
});
```

```
role = iam.Role(self, "MyRole",
    assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
    managed_policies=[
        iam.ManagedPolicy.from_aws_managed_policy_name(
            "service-role/AWSLambdaBasicExecutionRole"
        )
    ]
)

my_function = _lambda.CfnFunction(self, "HelloWorldFunction",
    runtime="nodejs24.x",
    role=role.role_arn,  # Pass the ARN string explicitly
    handler="index.handler",
    code=_lambda.CfnFunction.CodeProperty(
        zip_file=
        """
        exports.handler = async function(event) {
          return {
            statusCode: 200,
            body: JSON.stringify('Hello World!'),
          };
        };
        """
    )
)
```

```
Role role = Role.Builder.create(this, "MyRole")
    .assumedBy(new ServicePrincipal("lambda.amazonaws.com"))
    .managedPolicies(Arrays.asList(
        ManagedPolicy.fromAwsManagedPolicyName(
            "service-role/AWSLambdaBasicExecutionRole"
        )
    ))
    .build();

CfnFunction myFunction = CfnFunction.Builder.create(this, "HelloWorldFunction")
    .runtime("nodejs24.x")
    .role(role.getRoleArn())  // Pass the ARN string explicitly
    .handler("index.handler")
    .code(CfnFunction.CodeProperty.builder()
        .zipFile(
            "exports.handler = async function(event) {" +
            "  return {" +
            "    statusCode: 200," +
            "    body: JSON.stringify('Hello World!')," +
            "  };" +
            "};")
        .build())
    .build();
```

```
var role = new Role(this, "MyRole", new RoleProps
{
    AssumedBy = new ServicePrincipal("lambda.amazonaws.com"),
    ManagedPolicies = new[]
    {
        ManagedPolicy.FromAwsManagedPolicyName(
            "service-role/AWSLambdaBasicExecutionRole"
        )
    }
});

var myFunction = new CfnFunction(this, "HelloWorldFunction", new CfnFunctionProps
{
    Runtime = "nodejs24.x",
    Role = role.RoleArn,  // Pass the ARN string explicitly
    Handler = "index.handler",
    Code = new CfnFunction.CodeProperty
    {
        ZipFile = @"
        exports.handler = async function(event) {
          return {
            statusCode: 200,
            body: JSON.stringify('Hello World!'),
          };
        };
        "
    }
});
```

```
role := awsiam.NewRole(stack, jsii.String("MyRole"), &awsiam.RoleProps{
	AssumedBy: awsiam.NewServicePrincipal(jsii.String("lambda.amazonaws.com"), nil),
	ManagedPolicies: &[]awsiam.IManagedPolicy{
		awsiam.ManagedPolicy_FromAwsManagedPolicyName(jsii.String("service-role/AWSLambdaBasicExecutionRole")),
	},
})

myFunction := awslambda.NewCfnFunction(stack, jsii.String("HelloWorldFunction"), &awslambda.CfnFunctionProps{
	Runtime: jsii.String("nodejs24.x"),
	Role:    role.RoleArn(), // Pass the ARN string explicitly
	Handler: jsii.String("index.handler"),
	Code: &awslambda.CfnFunction_CodeProperty{
		ZipFile: jsii.String(`
		exports.handler = async function(event) {
		  return {
		    statusCode: 200,
		    body: JSON.stringify('Hello World!'),
		  };
		};
		`),
	},
})
```

##### 使用物件參考
<a name="_using_object_references"></a>

對於選取的屬性，您可以直接傳遞建構物件，而不是手動擷取其屬性。物件參考的支援會因屬性而異，並且可能會在新增屬性時隨著時間擴展。

當您在建構的 中傳遞物件參考時`props`，CDK 會將其解析為適當的字串值 （例如 ARN、名稱或其他識別符）。如果您稍後在建構執行個體上存取對應的 屬性，您會看到此解析字串值，而不是原始物件參考。

物件參考僅適用於建構的頂層屬性。複雜物件內的巢狀屬性需要明確的字串值。

下列範例顯示相同的 Lambda 函數，但使用角色物件而非角色的 ARN 字串：

**Example**  

```
const role = new iam.Role(this, 'MyRole', {
  assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
  managedPolicies: [
    iam.ManagedPolicy.fromAwsManagedPolicyName(
      'service-role/AWSLambdaBasicExecutionRole'
    ),
  ],
});

const myFunction = new lambda.CfnFunction(this, 'HelloWorldFunction', {
  runtime: 'nodejs24.x',
  role: role, // CDK resolves to role ARN automatically
  handler: 'index.handler',
  code: {
    zipFile: `
    exports.handler = async function(event) {
      return {
        statusCode: 200,
        body: JSON.stringify('Hello World!'),
      };
    };
  `}
});

// After creation, myFunction.role contains the resolved ARN string
```

```
const role = new iam.Role(this, 'MyRole', {
  assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
  managedPolicies: [
    iam.ManagedPolicy.fromAwsManagedPolicyName(
      'service-role/AWSLambdaBasicExecutionRole'
    )
  ]
});

const myFunction = new lambda.CfnFunction(this, "HelloWorldFunction", {
  runtime: 'nodejs24.x',
  role: role, // CDK resolves to role ARN automatically
  handler: 'index.handler',
  code: {
    zipFile: `
    exports.handler = async function(event) {
      return {
        statusCode: 200,
        body: JSON.stringify('Hello World!'),
      };
    };
  `}
});

// After creation, myFunction.role contains the resolved ARN string
```

```
role = iam.Role(self, "MyRole",
    assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
    managed_policies=[
        iam.ManagedPolicy.from_aws_managed_policy_name(
            "service-role/AWSLambdaBasicExecutionRole"
        )
    ]
)

my_function = _lambda.CfnFunction(self, "HelloWorldFunction",
    runtime="nodejs24.x",
    role=role,  # CDK resolves to role ARN automatically
    handler="index.handler",
    code=_lambda.CfnFunction.CodeProperty(
        zip_file=
        """
        exports.handler = async function(event) {
          return {
            statusCode: 200,
            body: JSON.stringify('Hello World!'),
          };
        };
        """
    )
)

# After creation, my_function.role contains the resolved ARN string
```

```
Role role = Role.Builder.create(this, "MyRole")
    .assumedBy(new ServicePrincipal("lambda.amazonaws.com"))
    .managedPolicies(Arrays.asList(
        ManagedPolicy.fromAwsManagedPolicyName(
            "service-role/AWSLambdaBasicExecutionRole"
        )
    ))
    .build();

CfnFunction myFunction = CfnFunction.Builder.create(this, "HelloWorldFunction")
    .runtime("nodejs24.x")
    .role(role)  // CDK resolves to role ARN automatically
    .handler("index.handler")
    .code(CfnFunction.CodeProperty.builder()
        .zipFile(
            "exports.handler = async function(event) {" +
            "  return {" +
            "    statusCode: 200," +
            "    body: JSON.stringify('Hello World!')," +
            "  };" +
            "};")
        .build())
    .build();

// After creation, myFunction.getRole() contains the resolved ARN string
```

```
var role = new Role(this, "MyRole", new RoleProps
{
    AssumedBy = new ServicePrincipal("lambda.amazonaws.com"),
    ManagedPolicies = new[]
    {
        ManagedPolicy.FromAwsManagedPolicyName(
            "service-role/AWSLambdaBasicExecutionRole"
        )
    }
});

var myFunction = new CfnFunction(this, "HelloWorldFunction", new CfnFunctionProps
{
    Runtime = "nodejs24.x",
    Role = role,  // CDK resolves to role ARN automatically
    Handler = "index.handler",
    Code = new CfnFunction.CodeProperty
    {
        ZipFile = @"
        exports.handler = async function(event) {
          return {
            statusCode: 200,
            body: JSON.stringify('Hello World!'),
          };
        };
        "
    }
});

// After creation, myFunction.Role contains the resolved ARN string
```

```
role := awsiam.NewRole(stack, jsii.String("MyRole"), &awsiam.RoleProps{
	AssumedBy: awsiam.NewServicePrincipal(jsii.String("lambda.amazonaws.com"), nil),
	ManagedPolicies: &[]awsiam.IManagedPolicy{
		awsiam.ManagedPolicy_FromAwsManagedPolicyName(jsii.String("service-role/AWSLambdaBasicExecutionRole")),
	},
})

myFunction := awslambda.NewCfnFunction(stack, jsii.String("HelloWorldFunction"), &awslambda.CfnFunctionProps{
	Runtime: jsii.String("nodejs24.x"),
	Role:    role, // CDK resolves to role ARN automatically
	Handler: jsii.String("index.handler"),
	Code: &awslambda.CfnFunction_CodeProperty{
		ZipFile: jsii.String(`
		exports.handler = async function(event) {
		  return {
		    statusCode: 200,
		    body: JSON.stringify('Hello World!'),
		  };
		};
		`),
	},
})

// After creation, *myFunction.Role() contains the resolved ARN string
```

### 使用 L2 建構
<a name="constructs-using"></a>

在下列範例中，我們透過從 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.Bucket.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.Bucket.html) L2 建構模組建立物件來定義 Amazon S3 儲存貯體：

**Example**  

```
import * as s3 from 'aws-cdk-lib/aws-s3';

// "this" is HelloCdkStack
new s3.Bucket(this, 'MyFirstBucket', {
  versioned: true
});
```

```
const s3 = require('aws-cdk-lib/aws-s3');

// "this" is HelloCdkStack
new s3.Bucket(this, 'MyFirstBucket', {
  versioned: true
});
```

```
import aws_cdk.aws_s3 as s3

# "self" is HelloCdkStack
s3.Bucket(self, "MyFirstBucket", versioned=True)
```

```
import software.amazon.awscdk.services.s3.*;

public class HelloCdkStack extends Stack {
    public HelloCdkStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public HelloCdkStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        Bucket.Builder.create(this, "MyFirstBucket")
                .versioned(true).build();
    }
}
```

```
using Amazon.CDK.AWS.S3;

// "this" is HelloCdkStack
new Bucket(this, "MyFirstBucket", new BucketProps
{
    Versioned = true
});
```

```
import (
	"github.com/aws/aws-cdk-go/awscdk/v2/awss3"
	"github.com/aws/jsii-runtime-go"
)

// stack is HelloCdkStack
awss3.NewBucket(stack, jsii.String("MyFirstBucket"), &awss3.BucketProps{
		Versioned: jsii.Bool(true),
	})
```

 `MyFirstBucket` 不是 AWS CloudFormation 建立的儲存貯體名稱。這是 CDK 應用程式內容中提供給新建構的邏輯識別符。[physicalName](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Resource.html#physicalname) 值將用於命名 AWS CloudFormation 資源。

## 使用第三方建構
<a name="constructs-work-third"></a>

 [Construct Hub](https://constructs.dev/search?q=&cdk=aws-cdk&cdkver=2&sort=downloadsDesc&offset=0) 是一項資源 AWS，可協助您探索來自第三方和開放原始碼 CDK 社群的其他建構。

### 撰寫您自己的建構
<a name="constructs-author"></a>

除了使用現有的建構，您也可以撰寫自己的建構，並讓任何人在其應用程式中使用這些建構。所有建構在 AWS CDK 中相等。建構程式庫中的 AWS 建構視為透過 NPM、 Maven或 發佈之第三方程式庫的建構PyPI。發佈到公司內部套件儲存庫的建構也會以相同方式處理。

若要宣告新的建構，請在 `constructs`套件中建立擴展[建構](https://docs.aws.amazon.com/cdk/api/v2/docs/constructs.Construct.html)基礎類別的類別，然後遵循初始化器引數的模式。

下列範例示範如何宣告代表 Amazon S3 儲存貯體的建構。S3 儲存貯體會在每次有人將檔案上傳到其中時傳送 Amazon Simple Notification Service (Amazon SNS) 通知。

**Example**  

```
export interface NotifyingBucketProps {
  prefix?: string;
}

export class NotifyingBucket extends Construct {
  constructor(scope: Construct, id: string, props: NotifyingBucketProps = {}) {
    super(scope, id);
    const bucket = new s3.Bucket(this, 'bucket');
    const topic = new sns.Topic(this, 'topic');
    bucket.addObjectCreatedNotification(new s3notify.SnsDestination(topic),
      { prefix: props.prefix });
  }
}
```

```
class NotifyingBucket extends Construct {
  constructor(scope, id, props = {}) {
    super(scope, id);
    const bucket = new s3.Bucket(this, 'bucket');
    const topic = new sns.Topic(this, 'topic');
    bucket.addObjectCreatedNotification(new s3notify.SnsDestination(topic),
      { prefix: props.prefix });
  }
}

module.exports = { NotifyingBucket }
```

```
class NotifyingBucket(Construct):

    def __init__(self, scope: Construct, id: str, *, prefix=None):
        super().__init__(scope, id)
        bucket = s3.Bucket(self, "bucket")
        topic = sns.Topic(self, "topic")
        bucket.add_object_created_notification(s3notify.SnsDestination(topic),
            s3.NotificationKeyFilter(prefix=prefix))
```

```
public class NotifyingBucket extends Construct {

    public NotifyingBucket(final Construct scope, final String id) {
        this(scope, id, null, null);
    }

    public NotifyingBucket(final Construct scope, final String id, final BucketProps props) {
        this(scope, id, props, null);
    }

    public NotifyingBucket(final Construct scope, final String id, final String prefix) {
        this(scope, id, null, prefix);
    }

    public NotifyingBucket(final Construct scope, final String id, final BucketProps props, final String prefix) {
        super(scope, id);

        Bucket bucket = new Bucket(this, "bucket");
        Topic topic = new Topic(this, "topic");
        if (prefix != null)
            bucket.addObjectCreatedNotification(new SnsDestination(topic),
                NotificationKeyFilter.builder().prefix(prefix).build());
     }
}
```

```
public class NotifyingBucketProps : BucketProps
{
    public string Prefix { get; set; }
}

public class NotifyingBucket : Construct
{
    public NotifyingBucket(Construct scope, string id, NotifyingBucketProps props = null) : base(scope, id)
    {
        var bucket = new Bucket(this, "bucket");
        var topic = new Topic(this, "topic");
        bucket.AddObjectCreatedNotification(new SnsDestination(topic), new NotificationKeyFilter
        {
            Prefix = props?.Prefix
        });
    }
}
```

```
type NotifyingBucketProps struct {
	awss3.BucketProps
	Prefix *string
}

func NewNotifyingBucket(scope constructs.Construct, id *string, props *NotifyingBucketProps) awss3.Bucket {
	var bucket awss3.Bucket
	if props == nil {
		bucket = awss3.NewBucket(scope, jsii.String(*id+"Bucket"), nil)
	} else {
		bucket = awss3.NewBucket(scope, jsii.String(*id+"Bucket"), &props.BucketProps)
	}
	topic := awssns.NewTopic(scope, jsii.String(*id+"Topic"), nil)
	if props == nil {
		bucket.AddObjectCreatedNotification(awss3notifications.NewSnsDestination(topic))
	} else {
		bucket.AddObjectCreatedNotification(awss3notifications.NewSnsDestination(topic), &awss3.NotificationKeyFilter{
			Prefix: props.Prefix,
		})
	}
	return bucket
}
```

**注意**  
我們的建構不是繼承自 `NotifyingBucket` `Bucket`，而是繼承自 `Construct`。我們使用合成而非繼承，將 Amazon S3 儲存貯體和 Amazon SNS 主題綁定在一起。一般而言，在開發 AWS CDK 建構時，合成優於繼承。

`NotifyingBucket` 建構函數具有典型的建構簽章：`scope`、 `id`和 `props`。最後一個引數 是選用的 （取得預設值 `{}`)`props`，因為所有 prop 都是選用的。（基本`Construct`類別不採用`props`引數。) 您可以在應用程式中定義此建構的執行個體，而不需要 `props`，例如：

**Example**  

```
new NotifyingBucket(this, 'MyNotifyingBucket');
```

```
new NotifyingBucket(this, 'MyNotifyingBucket');
```

```
NotifyingBucket(self, "MyNotifyingBucket")
```

```
new NotifyingBucket(this, "MyNotifyingBucket");
```

```
new NotifyingBucket(this, "MyNotifyingBucket");
```

```
NewNotifyingBucket(stack, jsii.String("MyNotifyingBucket"), nil)
```

或者，您可以使用 `props`（在 Java 中為額外的參數） 來指定要篩選的路徑字首，例如：

**Example**  

```
new NotifyingBucket(this, 'MyNotifyingBucket', { prefix: 'images/' });
```

```
new NotifyingBucket(this, 'MyNotifyingBucket', { prefix: 'images/' });
```

```
NotifyingBucket(self, "MyNotifyingBucket", prefix="images/")
```

```
new NotifyingBucket(this, "MyNotifyingBucket", "/images");
```

```
new NotifyingBucket(this, "MyNotifyingBucket", new NotifyingBucketProps
{
    Prefix = "/images"
});
```

```
NewNotifyingBucket(stack, jsii.String("MyNotifyingBucket"), &NotifyingBucketProps{
	Prefix: jsii.String("images/"),
})
```

一般而言，您也想要在建構模組上公開一些屬性或方法。將主題隱藏在您的建構之後並不實用，因為建構的使用者無法訂閱該主題。新增`topic`屬性可讓消費者存取內部主題，如下列範例所示：

**Example**  

```
export class NotifyingBucket extends Construct {
  public readonly topic: sns.Topic;

  constructor(scope: Construct, id: string, props: NotifyingBucketProps) {
    super(scope, id);
    const bucket = new s3.Bucket(this, 'bucket');
    this.topic = new sns.Topic(this, 'topic');
    bucket.addObjectCreatedNotification(new s3notify.SnsDestination(this.topic), { prefix: props.prefix });
  }
}
```

```
class NotifyingBucket extends Construct {

  constructor(scope, id, props) {
    super(scope, id);
    const bucket = new s3.Bucket(this, 'bucket');
    this.topic = new sns.Topic(this, 'topic');
    bucket.addObjectCreatedNotification(new s3notify.SnsDestination(this.topic), { prefix: props.prefix });
  }
}

module.exports = { NotifyingBucket };
```

```
class NotifyingBucket(Construct):

    def __init__(self, scope: Construct, id: str, *, prefix=None, **kwargs):
        super().__init__(scope, id)
        bucket = s3.Bucket(self, "bucket")
        self.topic = sns.Topic(self, "topic")
        bucket.add_object_created_notification(s3notify.SnsDestination(self.topic),
            s3.NotificationKeyFilter(prefix=prefix))
```

```
public class NotifyingBucket extends Construct {

    public Topic topic = null;

    public NotifyingBucket(final Construct scope, final String id) {
        this(scope, id, null, null);
    }

    public NotifyingBucket(final Construct scope, final String id, final BucketProps props) {
        this(scope, id, props, null);
    }

    public NotifyingBucket(final Construct scope, final String id, final String prefix) {
        this(scope, id, null, prefix);
    }

    public NotifyingBucket(final Construct scope, final String id, final BucketProps props, final String prefix) {
        super(scope, id);

        Bucket bucket = new Bucket(this, "bucket");
        topic = new Topic(this, "topic");
        if (prefix != null)
            bucket.addObjectCreatedNotification(new SnsDestination(topic),
                NotificationKeyFilter.builder().prefix(prefix).build());
     }
}
```

```
public class NotifyingBucket : Construct
{
    public readonly Topic topic;

    public NotifyingBucket(Construct scope, string id, NotifyingBucketProps props = null) : base(scope, id)
    {
        var bucket = new Bucket(this, "bucket");
        topic = new Topic(this, "topic");
        bucket.AddObjectCreatedNotification(new SnsDestination(topic), new NotificationKeyFilter
        {
            Prefix = props?.Prefix
        });
    }
}
```
若要在 Go 中執行此操作，我們需要一些額外的管道。我們的原始`NewNotifyingBucket`函數傳回 `awss3.Bucket`。我們需要透過建立`NotifyingBucket`結構來擴展`Bucket`以包含`topic`成員。然後，我們的函數會傳回此類型。  

```
type NotifyingBucket struct {
	awss3.Bucket
	topic awssns.Topic
}

func NewNotifyingBucket(scope constructs.Construct, id *string, props *NotifyingBucketProps) NotifyingBucket {
	var bucket awss3.Bucket
	if props == nil {
		bucket = awss3.NewBucket(scope, jsii.String(*id+"Bucket"), nil)
	} else {
		bucket = awss3.NewBucket(scope, jsii.String(*id+"Bucket"), &props.BucketProps)
	}
	topic := awssns.NewTopic(scope, jsii.String(*id+"Topic"), nil)
	if props == nil {
		bucket.AddObjectCreatedNotification(awss3notifications.NewSnsDestination(topic))
	} else {
		bucket.AddObjectCreatedNotification(awss3notifications.NewSnsDestination(topic), &awss3.NotificationKeyFilter{
			Prefix: props.Prefix,
		})
	}
	var nbucket NotifyingBucket
	nbucket.Bucket = bucket
	nbucket.topic = topic
	return nbucket
}
```

現在，消費者可以訂閱主題，例如：

**Example**  

```
const queue = new sqs.Queue(this, 'NewImagesQueue');
const images = new NotifyingBucket(this, '/images');
images.topic.addSubscription(new sns_sub.SqsSubscription(queue));
```

```
const queue = new sqs.Queue(this, 'NewImagesQueue');
const images = new NotifyingBucket(this, '/images');
images.topic.addSubscription(new sns_sub.SqsSubscription(queue));
```

```
queue = sqs.Queue(self, "NewImagesQueue")
images = NotifyingBucket(self, prefix="Images")
images.topic.add_subscription(sns_sub.SqsSubscription(queue))
```

```
NotifyingBucket images = new NotifyingBucket(this, "MyNotifyingBucket", "/images");
images.topic.addSubscription(new SqsSubscription(queue));
```

```
var queue = new Queue(this, "NewImagesQueue");
var images = new NotifyingBucket(this, "MyNotifyingBucket", new NotifyingBucketProps
{
    Prefix = "/images"
});
images.topic.AddSubscription(new SqsSubscription(queue));
```

```
	queue := awssqs.NewQueue(stack, jsii.String("NewImagesQueue"), nil)
	images := NewNotifyingBucket(stack, jsii.String("MyNotifyingBucket"), &NotifyingBucketProps{
		Prefix: jsii.String("/images"),
	})
	images.topic.AddSubscription(awssnssubscriptions.NewSqsSubscription(queue, nil))
```

## 進一步了解
<a name="constructs-learn"></a>

以下影片提供 CDK 建構的全面概觀，並說明如何在 CDK 應用程式中使用這些建構。

[![AWS Videos](http://img.youtube.com/vi/https://www.youtube.com/embed/PzU-i0rJPGw?rel=0/0.jpg)](http://www.youtube.com/watch?v=https://www.youtube.com/embed/PzU-i0rJPGw?rel=0)
