1. 複合パターンとは何ですか

複合パターンは、一般的に使用されるオブジェクト構造のデザインパターンです。これはオブジェクトをツリー構造に組み合わせて階層的な「部分-全体」の関係を表現し、クライアントが個々のオブジェクトとオブジェクト構成を一貫した方法で処理できるようにします。

2. 複合パターンの特性と利点

複合パターンの主な利点は次のとおりです。

  1. 階層的な複雑なオブジェクトを明確に定義し、オブジェクト階層の全体または一部を表現することで、新しいコンポーネントを追加しやすくします。
  2. 統一されたインターフェースを提供し、構成部品と個々のオブジェクトへのアクセスが一貫し、クライアントが単一のオブジェクトと複合オブジェクトを均一に使用できるようにします。

3. 複合パターンの適用シナリオ

  1. オブジェクトの部分-全体の階層を表現したい場合。
  2. クライアントが複合オブジェクトと個々のオブジェクトの違いを無視し、複合構造内のすべてのオブジェクトを均一に使用したい場合。

4. Golang での複合パターンの実装

例えば、eコマースアプリケーションの商品カタログは複合パターンの良い例です。カテゴリには他のカテゴリや製品が含まれ、電子製品カテゴリには電話、コンピュータが含まれ、電話にはiPhone、Samsung電話などが含まれます。

4.1 UML クラス図

Golang での複合パターン

4.2 例の紹介

この例では、Component(明らかにオブジェクト指向のインターフェース機能を使用している)を抽象基本クラスとし、Composite および Leaf の両方がこのインターフェースを実装し、それぞれコンテナオブジェクトと基本オブジェクトを表します。

4.3 実装ステップ 1: 抽象コンポーネントクラスを定義

4.3.1 抽象コンポーネントクラスのインターフェースを定義

// Component: 基本コンポーネントインターフェース、グループと個々の共通性を定義
type Component interface {
    Search(string)
}

4.3.2 抽象コンポーネントクラスの基本メソッドを実装

このステップは、通常、コンテナコンポーネントクラスおよびリーフコンポーネントクラスで具体的に実装されます。

4.4 実装ステップ 2: リーフコンポーネントクラスを定義

この具体クラスは階層内のボトムカテゴリまたはオブジェクトを表し、次のレイヤのオブジェクトを持っていません。

4.4.1 抽象コンポーネントクラスからの継承

Goでは、インターフェースの継承は Struct を通じてメソッドが実装される方法で実装されます。

4.4.2 リーフコンポーネントクラス固有のメソッドの実装

// Product: リーフノードを表し、製品を表し、子ノードを持つことはできません
type Product struct {
    Name string
}

// Search: 製品を検索
func (p *Product) Search(keyword string) {
    if strings.Contains(p.Name, keyword) {
        fmt.Printf("Product: '%s' はキーワード: '%s' を含んでいます\n", p.Name, keyword)
    }
}

4.5 実装ステップ 3: コンテナコンポーネントクラスを定義

このクラスは子オブジェクトを格納および管理するために使用され、一般的に子オブジェクトを管理および組織化するためのいくつかのメソッドを含みます。

4.5.1 抽象コンポーネントクラスからの継承

Goでも、このことは Struct を使用して実装されたインターフェースメソッドによって実装されます。

4.5.2 コンテナコンポーネントクラス固有のメソッドの実装

// Category: コンテナノードを表し、製品カテゴリを表し、子ノードを持つことができます
type Category struct {
    Name     string
    Children []Component
}

// Add: 子ノードを追加
func (c *Category) Add(child Component) {
    c.Children = append(c.Children, child)
}

// Remove: 子ノードを削除
func (c *Category) Remove(child Component) {
    // 特定の実装は省略されています
}

// Search: 製品を検索
func (c *Category) Search(keyword string) {
    fmt.Printf("Category: %s\n", c.Name)
    for _, composite := range c.Children {
        composite.Search(keyword)
    }
}

4.6 実装ステップ4: クライアントコードの例

構造体をインスタンス化し、それをツリー構造に組み立て、その後ツリー構造のアクセス操作を呼び出します。

func main() {
    root := &Category{Name: "ルート"}
    electronics := &Category{Name: "電子機器"}

    phone := &Product{Name: "電話"}
    tv := &Product{Name: "テレビ"}

    root.Add(electronics)
    electronics.Add(phone)
    electronics.Add(tv)

    root.Search("phone") // これはすべての子に検索します
}