设计模式篇——初探装饰器模式
文章目錄
1、裝飾器模式介紹
2、裝飾器模式類圖
3、裝飾器模式Demo實現(xiàn)(一個小鎮(zhèn)的拉面館)
4、裝飾器模式總結(jié)
裝飾器模式介紹:裝飾器模式可以在不修改任何底層代碼的情況下,給對象賦予新的職責(zé)(程序運行時的擴展,動態(tài)的將責(zé)任附加到對象上)。屬于結(jié)構(gòu)型設(shè)計模式。
類圖:
我們來看下裝飾器模式的類圖:
一個簡單的Demo(故鄉(xiāng)小鎮(zhèn)的一個面館):
?
? 在故鄉(xiāng)的一個小鎮(zhèn)上面,有一家面館,主營拉面。在這里你可以只點清湯面(SoupNoodle),也可以往里面加佐料,佐料有牛肉(Beef),魚丸(FishBall)還有菠菜(Spinach)。面館今天開張了。
? 這里的所有面條都基于一個抽象類BaseNoodle來實現(xiàn),這個抽象類有兩個抽象方法,獲取它的價格(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 } BaseNoodle? ?然后讓我們實現(xiàn)下我們最基礎(chǔ)的清湯面(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 } SoupNoodle? 這時候,我們來了第一位客人(張三),他要一碗帶牛肉作料的清湯面
于是乎,我們就實現(xiàn)了這樣一個類。
1 public class SoupNoodleWithBeef : BaseNoodle 2 { 3 private static double cost = 1; 4 public override string GetName() 5 { 6 return "清湯面" + ",牛肉"; 7 } 8 /// <summary> 9 /// 假設(shè)牛肉一份0.6元 10 /// </summary> 11 /// <returns></returns> 12 public override double Price() 13 { 14 return cost + 0.6; 15 } 16 } SoupNoodleWithBeef然后第二個客人進來了,是個可愛的小姑娘,她要一份加菠菜的清湯面。于是乎,我們又要實現(xiàn)這樣一個類。
?
1 public class SoupNoodleWithSpinach : BaseNoodle 2 { 3 private static double cost = 1; 4 public override string GetName() 5 { 6 return "清湯面" + ",菠菜"; 7 } 8 /// <summary> 9 /// 假設(shè)菠菜一份0.2元 10 /// </summary> 11 /// <returns></returns> 12 public override double Price() 13 { 14 return cost + 0.2; 15 } 16 } SoupNoodleWithSpinach我們一共有三種佐料,假設(shè)客人的口味都不同,那樣的話我們需要多少個繼承自BaseNoodle的子類呢? 沒錯,應(yīng)該是A(3,3)個6個子類。這樣顯然不行,假如我們后期有添加了新的佐料,蝦球,那樣我們的子類個數(shù)就是24個,況且誰又能保證客人只點一份相同的佐料呢?假如點兩份牛肉呢?我們的子類個數(shù)將呈現(xiàn)指數(shù)級別的增長。。。
這時候我們的裝飾器模式就登場了。
? 還是我們的面條基類抽象類,和清湯面(被裝飾者)類,在這個的基礎(chǔ)之上我們將不再寫很多針對細節(jié)的子類。我們首先實現(xiàn)一個佐料抽象類(SeasoningDecorator),這個抽象類也要繼承自BaseNoodle。它內(nèi)部有一個實例變量=》BaseNoodle
1 /// <summary> 2 /// 基礎(chǔ)佐料類 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? 此時,我們定義我們的具體佐料類,這些佐料類都繼承自SeasoningDecorator,而且內(nèi)部都存在一個實例變量=》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 } BeefDecorator 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 } FishBallDecorator 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 } Spinach? 這些具體的佐料類就是我們的裝飾器。因為它構(gòu)造函數(shù)接收一個BaseNoodle,所以我們可以這樣來實現(xiàn)對清湯面(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(); 點餐裝飾器模式總結(jié):
- 裝飾器屬于結(jié)構(gòu)型設(shè)計模式,很好的遵循了開閉原則。
- 裝飾器模式的裝飾者與被裝飾者有相同的超類型。
- 裝飾器模式可以在程序運行時,以組合的方式,動態(tài)的給對象添加行為(因為有相同的超類型,所以任何需要原始對象的場合,都可以用裝飾過的對象去替代它)。
- 裝飾器模式會出現(xiàn)很多的小的類型。
轉(zhuǎn)載于:https://www.cnblogs.com/liumengchen-boke/p/8725812.html
總結(jié)
以上是生活随笔為你收集整理的设计模式篇——初探装饰器模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通用mapper笔记
- 下一篇: 利益相关者系统描述