zoukankan      html  css  js  c++  java
  • 设计模式篇——初探装饰器模式

    文章目录

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

    装饰器模式总结:

    • 装饰器属于结构型设计模式,很好的遵循了开闭原则。
    • 装饰器模式的装饰者与被装饰者有相同的超类型。
    • 装饰器模式可以在程序运行时,以组合的方式,动态的给对象添加行为(因为有相同的超类型,所以任何需要原始对象的场合,都可以用装饰过的对象去替代它)。
    • 装饰器模式会出现很多的小的类型。
  • 相关阅读:
    第1课 Git、谁与争锋
    程序员最真实的10个瞬间
    程序员最真实的10个瞬间
    一文读懂前端缓存
    一文读懂前端缓存
    一文读懂前端缓存
    EF使用CodeFirst创建数据库和表
    EF使用CodeFirst创建数据库和表
    EF使用CodeFirst创建数据库和表
    ASP.NET MVC的过滤器笔记
  • 原文地址:https://www.cnblogs.com/liumengchen-boke/p/8725812.html
Copyright © 2011-2022 走看看