中秋快樂!!
Composite is a structural design pattern that lets you compose objects into tree structures and then work with these structures as if they were individual objects.
--Refactoring Guru
Composite(組合模式)是一種結構型設計模式,它允許你將物件組合成樹狀結構,然後以結構的方式處理它們(一層一層的),就好像它們是個別的物件一樣。
可以把組合模式想像成一顆有葉子的樹!
客戶端可以對一片葉子作存取的動作,
或是對存取某個枝葉。
我們先來看看它的UML圖~
組合模式通常在以下情況下使用:
需要表示 部分-整體 層次結構時:當你的應用程式中的對象具有部分-整體的層次結構,並且你想以一致的方式處理它們時,組合模式非常有用。
希望客戶端統一處理個別物件和組合物件:組合模式允許客戶端對待個別物件和組合物件,而無需關心它們的具體類型,從而簡化了客戶端程式碼。
需要構建具有層次結構的結構:當你需要構建具有內嵌(nested)結構的物件,例如樹狀結構、圖形界面元素,或者訂單和訂單項目等,組合模式能夠很好地支持這種需求。
希望新增或刪除部分或整體內容而不影響客戶端程式:組合模式使你能夠添加新的部分或整體物件,同時不需要修改客戶端程式碼,這提高了系統的可擴展性。
需要實現共享行為或運算:組合模式可以使你實現部分和整體物件之間的共享行為,從而避免程式碼的重複。
總之,組合模式適用於具有層次結構的物件,並且它能夠使客戶端程式碼更容易處理這些層次結構,從而提高程式碼的可維護性和可擴展性。
再用好吃的點心店舉例吧!
應景一點~
假設今天一家點心店賣了月餅和普洱茶~
首先先建立介面,展示架個還有品項
// 抽象點心類
abstract class Dessert
{
protected string name;
protected int priceNTD;
public Dessert(string name, int priceNTD)
{
this.name = name;
this.priceNTD = priceNTD;
}
public abstract int CalculateTotalPrice();
public virtual void Display()
{
Console.WriteLine("單點心:" + name + ",價格:" + priceNTD.ToString("C0") + " (新台幣)");
}
}
再來建立我們單一葉子物件!
// 葉子點心類 - 單一點心
class SingleDessert : Dessert
{
public SingleDessert(string name, int priceNTD) : base(name, priceNTD) { }
public override int CalculateTotalPrice()
{
return priceNTD;
}
}
題外話
"C0" 是 .NET 中的一種數字格式化字符串。在這個上下文中,它表示格式化為不帶小數位的整數。當你將數字格式化為 "C0" 時,它將以通用的貨幣格式顯示,但不包括小數部分~
接著是我想要點心店有組合餐~
並且提供優惠價!
// 複合點心類 - 點心組合
class ComboDessert : Dessert
{
private List<Dessert> desserts = new List<Dessert>();
public ComboDessert(string name) : base(name, 0)
{
// 計算並設定合併的優惠價格
CalculateDiscountedPrice();
}
public void AddDessert(Dessert dessert)
{
desserts.Add(dessert);
// 在新增點心時,重新計算合併的優惠價格
CalculateDiscountedPrice();
}
public void RemoveDessert(Dessert dessert)
{
desserts.Remove(dessert);
// 在刪除點心時,重新計算合併的優惠價格
CalculateDiscountedPrice();
}
private void CalculateDiscountedPrice()
{
// 計算合併的優惠價格,例如打折或組合優惠
int totalRegularPrice = 0;
foreach (var dessert in desserts)
{
totalRegularPrice += dessert.CalculateTotalPrice();
}
// 假設這裡有一個 10% 的組合優惠
int discount = (int)(totalRegularPrice * 0.10);
// 設定合併的優惠價格為總價減去折扣
this.priceNTD = totalRegularPrice - discount;
}
public override int CalculateTotalPrice()
{
return priceNTD;
}
public override void Display()
{
Console.WriteLine("點心套餐:" + name);
Console.WriteLine("包含以下點心:");
foreach (var dessert in desserts)
{
dessert.Display();
}
Console.WriteLine("合併的優惠價格:" + priceNTD.ToString("C0") + " (新台幣)");
}
}
最後
我們的客戶端程式碼~
class Program
{
static void Main(string[] args)
{
// 創建點心
var mooncake = new SingleDessert("月餅", 80);
var puErTea = new SingleDessert("普洱茶", 40);
// 創建點心套餐
var dessertCombo = new ComboDessert("特別組合");
dessertCombo.AddDessert(mooncake);
dessertCombo.AddDessert(puErTea);
// 顯示點心和點心套餐
mooncake.Display();
puErTea.Display();
dessertCombo.Display();
Console.ReadLine();
}
}
output: