设计模式——装饰模式(Decorator Pattern)

装饰模式

1、背景

假设奶茶店有两种茶,果茶(fruit tea)和奶茶(milky tea),同时这两种茶饮料可以添加不同的配料 果肉(pulp)或者蔗糖(sugar),茶品可以和配料进行组合,所以可以得到:

  • 1、pulp_fruit_tea(果茶加果肉)
  • 2、pulp_milky_tea(奶茶加果肉)
  • 3、sugar_fruit_tea(果茶加糖)
  • 4、sugar_milky_tea(奶茶加糖)
  • 5、 fruit_tea(果茶)
  • 6、milky_tea(奶茶)
    日后还会增加新的茶品和配料。

1、采用单一继承的方式的UML图: 有多少个技能就写多少个子类来继承这个tea类。
在这里插入图片描述
可以明显发现一个问题:就是随着物品修饰种类的增加,继承的类也越来越多,每增加一个技能可以组合出N个子类,那不就要加到天荒地老?
2、直接抽象一个tea类,里面包含了所有的配料。

在这里插入图片描述
这样子有多少个角色就增加多少个子类就可以了,不用根据技能增加类,避免造成子类爆炸,但是,每个角色的技能是可以叠加使用的,角色越多或者技能叠加种类越多,那么就要在超类增加越多的方法,而且直接修改超类不符合开闭原则(超类对扩展开放,对修改关闭)。

综上:

  • 装饰模式实际上是一直提倡的组合代替继承的实践方式,个人认为要理解装饰者模式首先需要理解为什么需要组合代替继承,继承又是为什么让人深恶痛绝.

为什么建议使用组合代替继承?
面向对象的特性有继承与封装,但两者却又有一点矛盾,继承意味子类依赖了父类中的实现,一旦父类中改变实现则会对子类造成影响,这是打破了封装性的一种表现. 而组合就是巧用封装性来实现继承功能的代码复用.

2、定义

1.定义:

-装饰器模式又名包装(Wrapper)模式。动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

  • 装饰器模式以对客户端透明的方式拓展对象的功能,是继承关系的一种替代方案。

在这里插入图片描述
UML关系图说明:

继承关系:实线、空三角箭头 ,具体装饰继承Decorator,Decorator继承Component; 聚合:实线、菱形

  • 1、抽象构件(Component)角色:一个抽象接口。装饰对象和被装饰对象【具体组件对象】共有的父类接口。这样客户端对象就能以相同的方式操作具体组件对象和装饰对象【或者说可以将装饰类作为组件类看待】

  • 2、具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。装饰模式是为这个基类动态添加新功能。

  • 3、装饰(Decorator)角色:装饰对象包含一个真实组件对像的引用。它的作用是接受需要扩展功能的具体组件类;实现抽象组件接口,使得在动态添加功能时具体装饰类和具体组件类用法相同,使模式更加灵活。

  • 4、具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。

3、特征

  • 需要扩展一个类的功能或给一个类增加附加责任。
  • 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
  • 需要增加由一些基本功能的排列组合而产生的非常大量的功能

优点:

  • 1、装饰这模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活 通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合装饰者模式有很好地可扩展性
  • 2、装饰类和被装饰类可以独立发展,而不会相互耦合。Component类无须知道Decorator类,而Decorator也不用知道具体的构件,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

缺点:

  • 装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变的更复杂。并且更多的对象会是的差错变得困难,特别是这些对象看上去都很像。

4、应用

#include <iostream>
using namespace std;
class Component//抽象构件(Component)角色
{
public:
     virtual void Operation() = 0;//虚析构函数
};
class ConcreteComponent : public Component//具体构件(ConcreteComponent)角色
{
public:
     void Operation()//实例化Operation()
     {
          cout<<"I am no decoratored ConcreteComponent"<<endl;
     }
};
class Decorator : public Component//装饰(Decorator)角色
{
public:
     Decorator(Component *pComponent) : m_pComponentObj(pComponent) {}//构造函数
     void Operation()
     {
          if (m_pComponentObj != NULL)
          {
               m_pComponentObj->Operation();
          }
     }
protected:
     Component *m_pComponentObj;
};
class ConcreteDecoratorA : public Decorator//具体装饰(ConcreteDecorator)角色
{
public:
     ConcreteDecoratorA(Component *pDecorator) : Decorator(pDecorator){}
     void Operation()
     {
          AddedBehavior();
          Decorator::Operation();
     }
     void  AddedBehavior()
     {
          cout<<"This is added behavior A."<<endl;
     }
};
class ConcreteDecoratorB : public Decorator
{
public:
     ConcreteDecoratorB(Component *pDecorator) : Decorator(pDecorator){}
     void Operation()
     {
          AddedBehavior();
          Decorator::Operation();
     }
     void  AddedBehavior()
     {
          cout<<"This is added behavior B."<<endl;
     }
};
int main()
{
     Component *pComponentObj = new ConcreteComponent();//客户需求实例化
     //下面开始添加修饰,增加不同 的客户需求
     //只添加A修饰
     Decorator *pDecoratorAOjb = new ConcreteDecoratorA(pComponentObj);//基类指针指向派生类对象,也就是抽象类修饰调用具体类修饰函数
     pDecoratorAOjb->Operation();
     cout<<"============================================="<<endl;
     //只添加B修饰
     Decorator *pDecoratorBOjb = new ConcreteDecoratorB(pComponentObj);
     pDecoratorBOjb->Operation();
     cout<<"============================================="<<endl;
     //先添加B修饰的基础上,再一次添加A的修饰
     Decorator *pDecoratorBAOjb = new ConcreteDecoratorB(pDecoratorAOjb);
     pDecoratorBAOjb->Operation();
     cout<<"============================================="<<endl;
     delete pDecoratorBAOjb;
     pDecoratorBAOjb = NULL;
     delete pDecoratorBOjb;
     pDecoratorBOjb = NULL;
     delete pDecoratorAOjb;
     pDecoratorAOjb = NULL;
     delete pComponentObj;
     pComponentObj = NULL;
}

在这里插入图片描述

参考

1、https://www.cnblogs.com/xuwendong/p/10180943.html
2、https://www.jianshu.com/p/d7a9208c6829
3、https://blog.csdn.net/a19881029/article/details/8980503

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值