装饰者模式--Head First设计模式【笔记】

星巴克:世界闻名的咖啡连锁店。他的订单系统,如果你有兴趣了解下的话,跟我来吧。

一、他们原先的设计

//Beverage(饮料)是一个抽象类,店里所提供的饮料都必须继承此类。
public abstract class Beverage { public string description = "Unknown Beverage"; //description(描述),店里面所有饮料的描述。
public string getDescription() //获取饮料描述 { return description; } public abstract double cost();//价格,由子类自己实现。 }

HouseBlend(家常咖啡):星巴克首选咖啡。

 public  class HouseBlend:Beverage 
    {
        public HouseBlend() 
        {
            description = "House Blend Coffee";
        }

        public override double cost()
        {
            return 0.89;
        }
    }

Espresso(特浓咖啡)素有“咖啡之魂”的美称。对于咖啡馆来说,“没卖 ‘Espresso’ 的咖啡馆就不是咖啡馆”,可见 “Espresso“ 重要性。

  public  class Espresso:Beverage 
    {
        public Espresso() 
        {
            description = "Espresso";
        }

        public override double cost()
        {
            return 1.99;
        }
    }

现在市场需求出现新的变化:我要红豆特浓咖啡(特浓咖啡+红豆)

加个新类HongDouEspresso 如下?那么如果我换个口味(即新的配料+特浓咖啡)要豆浆特浓咖啡(豆浆+特浓咖啡),那不是又要新建一个类?如果我一天换个口味,那么这个系统存在的每一天不是都要升级一次?这是多么恐怖且二逼的系统啊!!!!

那么,有没有办法把这些配料“动态地”加到咖啡里面来,而不是像下面的代码那样写死在代码中。

 public  class HongDouEspresso:Beverage 
    {
        public Espresso() 
        {
            description = "HongDouEspresso";
        }

        public override double cost()
        {
            return 2.29;
        }
    }

再想想我们OO设计原则
1.找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
2.针对接口编程,而不是针对实现编程。
3.多用组合,少用继承。
4.为了交互对象之间的松耦合设计而努力。
5.类应该对扩展开发,对修改关闭。

二、星巴克订单系统二代出来了:装饰者模式

1  public abstract  class Beverage//饮料的抽象类,即组件的抽象类
2     {
3        public   string description = "Unknown Beverage";
4         public virtual  string getDescription() //用虚方法,因为我想要把后面加进来的配料名称也显示出来。
5         {
6             return description;
7         }
8         public abstract double cost();
9     }

5.类应该对扩展开发,对修改关闭。所以特浓咖啡,家常咖啡的类代码不变。如下

//特浓咖啡 
public  class Espresso:Beverage 
    {
        public Espresso() 
        {
            description = "Espresso";
        }

        public override double cost()
        {
            return 1.99;
        }
    }
//家常咖啡
public  class HouseBlend:Beverage 
    {
        public HouseBlend() 
        {
            description = "House Blend Coffee";
        }

        public override double cost()
        {
            return 0.89;
        }
    }

神奇的配料代码来了

//配料的抽象类 
 public abstract  class CondimentDecorator:Beverage 
    {
             //每个配料都要实现的抽象类,继承Beverage 是为了保存对某个Beverage 对象的引用,实现多态的“类型匹配”。
    }

 

//红豆(HongDou配料的实现代码)
public class HongDou:CondimentDecorator { Beverage beverage;//用实例变量来记录饮料(“这些配料“动态地”加到咖啡里面来,而不是像下面的代码那样写死在代码中。”关键实现) //把饮料当做构造函数参数,是为了把饮料记录到实例变量中。(“这些配料“动态地”加到咖啡里面来,而不是像下面的代码那样写死在代码中。”关键实现)
public HongDou(Beverage beverage) { this.beverage = beverage; } public override string getDescription() { return beverage.getDescription() + ",HongDou";//我们希望不仅记录饮料,还记录配料。 } public override double cost() {
//要计算带HongDou配料的饮料价格,首先把调用委托给被装饰对象(组件),以计算价格,如何加上HongDou价格,得到最终价格。
return 0.35 + beverage.cost(); } }

 

//豆浆(DouJiang)的代码跟红豆(HongDou) 代码类似,就不多做阐述了。
public  class DouJiang:CondimentDecorator 
    {
       Beverage beverage;

       public DouJiang(Beverage beverage)
       {
           this.beverage = beverage;
       }
        public override string getDescription()
        {
            return beverage.getDescription() + ",DouJiang";
        }

        public override double cost()
        {
            return 0.20 + beverage.cost();
        }
    }

重要时刻:调试下--小二,给爷上一大杯 红豆双豆浆家常咖啡!

 static void Main(string[] args)
        {
            
            Beverage beverage2 = new HouseBlend();//创建一个组件对象--家常咖啡
            beverage2 = new DouJiang(beverage2);//豆浆装饰
            beverage2 = new DouJiang(beverage2);
            beverage2 = new HongDou(beverage2);//红豆装饰
            Console.WriteLine(beverage2.getDescription() + "     " + "$" + beverage2.cost());
            Console.ReadKey();
        }

小二:来了,大爷1.64美刀。

到这来星巴克的订单系统之装饰者模式基本是说完了。

突然,大爷冒出来说:小二,我买这么多,你也不给我打个折什么的啊?至少豆浆给我打个七五折吧?

我们装饰者模式不是万能的,遇到这种情况就不好解决。那怎么办?咱们先回去想想!!!

转载于:https://www.cnblogs.com/Techlink/archive/2012/08/27/2658289.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值