设计模式之9 - 装饰模式Decorator

来源:互联网 发布:缸中之脑 知乎 编辑:程序博客网 时间:2024/06/05 08:11

        我们经常会遇到这种问题,当一个类出现非常多的选择,比如 咖啡,要加 糖、抹茶、香草、牛奶……,那么多调味品,在这种情况下,考虑通过继承的方式是否合理?你会得到 很多种咖啡类,牛奶咖啡、抹茶咖啡、牛奶椰蓉咖啡、香草黑糖咖啡、曲奇巧克力蛋奶咖啡……,好像很不靠谱对吧?

        发现了 上面的 子类爆炸问题 后,你可能会问,我需要定义那么多的子类吗? 咖啡就是咖啡,其他的只是酌料而已。

        装饰者模式 相当于在类外面加上包装,生成新的类,这样做的好处 一是 减少了子类的数量(没有了组合类),二是可以在运行时动态组合,更加灵活。


        还是以 咖啡为例,通过代码来进行说明:

// Caffe抽象基类 - Componentclass ICaffe{public:    virtual float getPrice();};// Caffe实现类 - ConcreteComponentclass Caffe : public ICaffe{public:    virtual float getPrice() { return 10; };};// Decortaorclass Decorator : public ICaffe{public:    Decorator(Icaffe* pComponent)        : m_pComponent(pComponent)    {    }public:    virtual float getPrice()    {         return m_pComponent->getPrice();    }protected:    ICaffe* m_pComponent;};// ConcreteDecoratorclass MochaCaffe : public Decorator{public:    MochaCaffe(Icaffe* pComponent)        : Decorator(pComponent)    {    }public:    virtual float getPrice()    {         return 0.5 + m_pComponent->getPrice();    }};
        装饰者模式 通过相同的抽象基类,能够实现多层的包装,这样做的缺点是 其内容定义往往不是很清晰,就好像我们收到一个程序员朋友寄来的礼物,拆开 天猫的塑料袋,里面是个纸箱子,拆开纸箱子里面是一个盒子,拆开盒子发现里面是一个信封,拆开信封发现里面有张纸,清晰得写着四个大字:“Hello World!”

        尽管大家众说纷纭,但作者并不推崇 装饰者模式,相反,在复杂性和可读性之间抉择,我认为这是一个失败的模式,也许下面的实现会更容易理解:

// Caffe类class Caffe{public:    virtual float getPrice() { return 10; }};// 修饰组件类enum Dressing_Type { 抹茶,糖,辣椒,牛奶,香草,巧克力,奶昔,… }class Dressing{public:    Dressing_Type type;  // 修饰类型    float price;};// 具体实现类class DressedCaffe : public Caffe{public:    virtual float getPrice()    {         // 遍历vector求和    }protected:    Caffe             m_Caffe;    vector<Dressing>  m_vecDressing;};
        只需要扩展Dressing的属性定义即可,这里不去比较哪种方案的优劣,其实每个人都有自己的代码习惯,符合自己的才是最好的,PS:设计模式里面真正应用最多的也就那么几种,用之前先要考虑这是否必要,强用设计模式 着实是初学者 一个非常大的误区!
2 0