文章目錄
1、裝飾器模式介紹
2、裝飾器模式類圖
3、裝飾器模式Demo實現(一個小鎮的拉麪館)
4、裝飾器模式總結
裝飾器模式介紹:裝飾器模式可以在不修改任何底層代碼的情況下,給對象賦予新的職責(程序運行時的擴展,動態的將責任附加到對象上)。屬於結構型設計模式。
類圖:
我們來看下裝飾器模式的類圖:
一個簡單的Demo(故鄉小鎮的一個麪館):
在故鄉的一個小鎮上面,有一家麪館,主營拉麪。在這裏你可以只點清湯麪(SoupNoodle),也可以往裏面加佐料,佐料有牛肉(Beef),魚丸(FishBall)還有菠菜(Spinach)。麪館今天開張了。
這裏的所有面條都基於一個抽象類BaseNoodle來實現,這個抽象類有兩個抽象方法,獲取它的價格(double Price()),獲取它的名字(string GetName())。
1 /// <summary> 2 /// 麪條抽象類 3 /// </summary> 4 public abstract class BaseNoodle 5 { 6 /// <summary> 7 /// 價格 8 /// </summary> 9 /// <returns></returns> 10 public abstract double Price(); 11 /// <summary> 12 /// 獲取名稱 13 /// </summary> 14 /// <returns></returns> 15 public abstract string GetName(); 16 }
然後讓我們實現下我們最基礎的清湯麪(SoupNoodle),清湯麪的價格是1塊錢(嗯,還蠻實惠的)
1 /// <summary> 2 /// 清湯麪 3 /// </summary> 4 public class SoupNoodle : BaseNoodle 5 { 6 private static double cost = 1; 7 public override string GetName() 8 { 9 return "清湯麪"; 10 } 11 public override double Price() 12 { 13 return cost; 14 } 15 }
這時候,我們來了第一位客人(張三),他要一碗帶牛肉作料的清湯麪
於是乎,我們就實現了這樣一個類。
1 public class SoupNoodleWithBeef : BaseNoodle 2 { 3 private static double cost = 1; 4 public override string GetName() 5 { 6 return "清湯麪" + ",牛肉"; 7 } 8 /// <summary> 9 /// 假設牛肉一份0.6元 10 /// </summary> 11 /// <returns></returns> 12 public override double Price() 13 { 14 return cost + 0.6; 15 } 16 }
然後第二個客人進來了,是個可愛的小姑娘,她要一份加菠菜的清湯麪。於是乎,我們又要實現這樣一個類。
1 public class SoupNoodleWithSpinach : BaseNoodle 2 { 3 private static double cost = 1; 4 public override string GetName() 5 { 6 return "清湯麪" + ",菠菜"; 7 } 8 /// <summary> 9 /// 假設菠菜一份0.2元 10 /// </summary> 11 /// <returns></returns> 12 public override double Price() 13 { 14 return cost + 0.2; 15 } 16 }
我們一共有三種佐料,假設客人的口味都不同,那樣的話我們需要多少個繼承自BaseNoodle的子類呢? 沒錯,應該是A(3,3)個6個子類。這樣顯然不行,假如我們後期有添加了新的佐料,蝦球,那樣我們的子類個數就是24個,況且誰又能保證客人只點一份相同的佐料呢?假如點兩份牛肉呢?我們的子類個數將呈現指數級別的增長。。。
這時候我們的裝飾器模式就登場了。
還是我們的麪條基類抽象類,和清湯麪(被裝飾者)類,在這個的基礎之上我們將不再寫很多針對細節的子類。我們首先實現一個佐料抽象類(SeasoningDecorator),這個抽象類也要繼承自BaseNoodle。它內部有一個實例變量=》BaseNoodle
1 /// <summary> 2 /// 基礎佐料類 3 /// </summary> 4 public abstract class SeasoningDecorator : BaseNoodle 5 { 6 private BaseNoodle _baseNoodle = null; 7 public SeasoningDecorator(BaseNoodle baseNoodle) 8 { 9 _baseNoodle = baseNoodle; 10 } 11 12 public override string GetName() 13 { 14 return this._baseNoodle.GetName(); 15 } 16 17 public override double Price() 18 { 19 return this._baseNoodle.Price(); 20 } 21 }
此時,我們定義我們的具體佐料類,這些佐料類都繼承自SeasoningDecorator,而且內部都存在一個實例變量=》BaseNoodle。
1 /// <summary> 2 /// 牛肉 3 /// </summary> 4 public class BeefDecorator: SeasoningDecorator 5 { 6 private static double cost = 0.6; 7 private BaseNoodle _baseNoodle = null; 8 public BeefDecorator(BaseNoodle baseNoodle) : base(baseNoodle) 9 { 10 _baseNoodle = baseNoodle; 11 } 12 public override string GetName() 13 { 14 return this._baseNoodle.GetName() + ",牛肉"; 15 } 16 public override double Price() 17 { 18 return this._baseNoodle.Price() + cost; 19 } 20 }
1 /// <summary> 2 /// 魚丸 3 /// </summary> 4 public class FishBallDecorator : SeasoningDecorator 5 { 6 private static double cost = 0.4; 7 private BaseNoodle _baseNoodle = null; 8 public override string GetName() 9 { 10 return this._baseNoodle.GetName() + ",魚丸"; 11 } 12 public FishBallDecorator(BaseNoodle baseNoodle) : base(baseNoodle) 13 { 14 _baseNoodle = baseNoodle; 15 } 16 public override double Price() 17 { 18 return this._baseNoodle.Price() + cost; 19 } 20 }
1 /// <summary> 2 /// 菠菜 3 /// </summary> 4 public class Spinach : SeasoningDecorator 5 { 6 private static double cost = 0.2; 7 private BaseNoodle _baseNoodle = null; 8 public override string GetName() 9 { 10 return this._baseNoodle.GetName() + ",菠菜"; 11 } 12 public Spinach(BaseNoodle baseNoodle) : base(baseNoodle) 13 { 14 _baseNoodle = baseNoodle; 15 } 16 public override double Price() 17 { 18 return this._baseNoodle.Price() + cost; 19 } 20 }
這些具體的佐料類就是我們的裝飾器。因爲它構造函數接收一個BaseNoodle,所以我們可以這樣來實現對清湯麪(SoupNoodle)的裝飾:
1 //定義清湯麪 2 BaseNoodle baseSoupNoodle = new SoupNoodle(); 3 //添加一份牛肉 4 baseSoupNoodle = new BeefDecorator(baseSoupNoodle); 5 //添加一份魚丸 6 baseSoupNoodle = new FishBallDecorator(baseSoupNoodle); 7 //添加一份菠菜 8 baseSoupNoodle = new Spinach(baseSoupNoodle); 9 //再添加一份牛肉 10 baseSoupNoodle = new BeefDecorator(baseSoupNoodle); 11 Console.WriteLine($"點了一份{baseSoupNoodle.GetName()},價格爲{baseSoupNoodle.Price()}"); 12 Console.Read();
裝飾器模式總結:
- 裝飾器屬於結構型設計模式,很好的遵循了開閉原則。
- 裝飾器模式的裝飾者與被裝飾者有相同的超類型。
- 裝飾器模式可以在程序運行時,以組合的方式,動態的給對象添加行爲(因爲有相同的超類型,所以任何需要原始對象的場合,都可以用裝飾過的對象去替代它)。
- 裝飾器模式會出現很多的小的類型。