當需要以統一介面處理「部分-整體」階層結構時,Composite 模式讓客戶端程式碼無需區分單一物件與容器物件,大幅簡化遞迴結構的操作邏輯。
Draw())。支援基本圖形與複合圖形(圖形群組)統一繪製。
using System;
using System.Collections.Generic;
// Component 介面
public interface IShape
{
void Draw();
}
// Leaf: 直線
public class Line : IShape
{
private readonly double _x1, _y1, _x2, _y2;
public Line(double x1, double y1, double x2, double y2)
=> (_x1, _y1, _x2, _y2) = (x1, y1, x2, y2);
public void Draw() => Console.WriteLine($"Drawing line ({_x1},{_y1}) -> ({_x2},{_y2})");
}
// Leaf: 圓形
public class Circle : IShape
{
private readonly double _x, _y, _radius;
public Circle(double x, double y, double radius)
=> (_x, _y, _radius) = (x, y, radius);
public void Draw() => Console.WriteLine($"Drawing circle at ({_x},{_y}) radius {_radius}");
}
// Composite: 圖形群組
public class Drawing : IShape
{
private readonly List _shapes = new();
public void Add(IShape shape) => _shapes.Add(shape);
public void Draw()
{
Console.WriteLine("Drawing group:");
foreach (var shape in _shapes)
shape.Draw(); // 遞迴委派
}
}
public class Program
{
public static void Main()
{
var shapes = new IShape[]
{
new Line(0, 0, 10, 10),
new Circle(5, 5, 3),
new Drawing
{
new Line(1, 1, 2, 2),
new Circle(3, 3, 1.5)
}
};
foreach (var shape in shapes)
shape.Draw(); // 客戶端無需判斷型別
}
}
輸出結果:
Drawing line (0,0) -> (10,10) Drawing circle at (5,5) radius 3 Drawing group: Drawing line (1,1) -> (2,2) Drawing circle at (3,3) radius 1.5
public class Drawing : IShape
{
private readonly List _shapes = new();
public void Add(IShape shape) => _shapes.Add(shape);
public void Remove(IShape shape) => _shapes.Remove(shape);
public IShape GetChild(int index) => _shapes[index];
public void Draw()
{
foreach (var shape in _shapes)
shape.Draw();
}
}
| 優點 | 缺點 |
|---|---|
| 簡化客戶端:統一介面處理樹狀結構 | 設計過於通用:可能允許不合理的組合(如將圖形加入葉節點) |
| 易於新增元件型別 | 難以限制容器內容:需在執行時檢查或引入型別約束 |
| 符合開放封閉原則 | 效能開銷:遞迴遍歷深層樹狀結構可能較慢 |
FileSystemInfo)。IList<T> 或 ICollection<T>。Add 方法加入型別檢查或使用泛型約束。IEnumerable<IShape> 方便 LINQ 查詢。Composite 模式將「部分-整體」階層抽象為統一介面,讓客戶端程式碼免於處理遞迴邏輯與型別判斷。它是處理樹狀結構的基石模式。下一篇將介紹 State 狀態模式。