設計模式篇——初探裝飾器模式

文章目錄

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     }
BaseNoodle

   然後讓我們實現下我們最基礎的清湯麪(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

  這時候,我們來了第一位客人(張三),他要一碗帶牛肉作料的清湯麪

於是乎,我們就實現了這樣一個類。

 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     }
SoupNoodleWithBeef

然後第二個客人進來了,是個可愛的小姑娘,她要一份加菠菜的清湯麪。於是乎,我們又要實現這樣一個類。

 

 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     }
SoupNoodleWithSpinach

我們一共有三種佐料,假設客人的口味都不同,那樣的話我們需要多少個繼承自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

  此時,我們定義我們的具體佐料類,這些佐料類都繼承自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     }
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

  這些具體的佐料類就是我們的裝飾器。因爲它構造函數接收一個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();
點餐

裝飾器模式總結:

  • 裝飾器屬於結構型設計模式,很好的遵循了開閉原則。
  • 裝飾器模式的裝飾者與被裝飾者有相同的超類型。
  • 裝飾器模式可以在程序運行時,以組合的方式,動態的給對象添加行爲(因爲有相同的超類型,所以任何需要原始對象的場合,都可以用裝飾過的對象去替代它)。
  • 裝飾器模式會出現很多的小的類型。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章