Loading

设计模式篇——初探装饰器模式

文章目录

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();
点餐

装饰器模式总结:

  • 装饰器属于结构型设计模式,很好的遵循了开闭原则。
  • 装饰器模式的装饰者与被装饰者有相同的超类型。
  • 装饰器模式可以在程序运行时,以组合的方式,动态的给对象添加行为(因为有相同的超类型,所以任何需要原始对象的场合,都可以用装饰过的对象去替代它)。
  • 装饰器模式会出现很多的小的类型。
posted @ 2018-04-06 02:05  3WLineCode  阅读(247)  评论(0编辑  收藏  举报