cover

Composite 模式:部分與整體一致操作

Composite 模式把物件組合成樹狀結構,讓你對單一物件與物件組合同樣操作。

classDiagram
    class ProductCategory {
        <<abstract>>
        -name : String
        +add(component) void
        +remove(component) void
        +display(indent)* void
    }
    class Product {
        -price : Number
        +display(indent) void
    }
    class Category {
        -children : ProductCategory[]
        +add(component) void
        +remove(component) void
        +display(indent) void
    }
    ProductCategory <|-- Product
    ProductCategory <|-- Category
    Category o-- ProductCategory : children

使用情境

  1. 產品分類:產品與分類目錄。
  2. 檔案系統:檔案與資料夾。
  3. UI 元件樹:容器與子元件。

實作範例

Composite 模式:樹狀結構統一處理

class ProductCategory {
  constructor(name) {
    this.name = name;
  }
 
  add(component) {
    throw new Error('Method not supported');
  }
 
  remove(component) {
    throw new Error('Method not supported');
  }
 
  display(indent = 0) {
    throw new Error('display must be implemented');
  }
}
 
class Product extends ProductCategory {
  constructor(name, price) {
    super(name);
    this.price = price;
  }
 
  display(indent = 0) {
    const indentation = ' '.repeat(indent);
    console.log(`${indentation}- ${this.name}: $${this.price}`);
  }
}
 
class Category extends ProductCategory {
  constructor(name) {
    super(name);
    this.children = [];
  }
 
  add(component) {
    this.children.push(component);
  }
 
  remove(component) {
    const index = this.children.indexOf(component);
    if (index > -1) {
      this.children.splice(index, 1);
    }
  }
 
  display(indent = 0) {
    const indentation = ' '.repeat(indent);
    console.log(`${indentation}+ ${this.name}`);
    this.children.forEach(child => child.display(indent + 2));
  }
}
 
const electronics = new Category('Electronics');
const phones = new Category('Phones');
 
phones.add(new Product('iPhone 15', 999));
phones.add(new Product('Samsung S24', 899));
 
electronics.add(phones);
electronics.display();

優點

  • 客戶端使用方式一致
  • 結構清楚,易於擴充

缺點

  • 規則複雜時較難限制組合

延伸閱讀