装饰模式: 一种结构型设计模式
应用场景:
想要动态的给一个对象添加功能, 即希望可以根据需求对现有对象添加不同的功能, 以及不同功能的相互组合.
如果通过继承实现功能增加, 则为了各功能的组合, 需要将不同功能排列组合形成数量爆炸的一堆子类.
此时可以考虑装饰模式
举例:
游戏中的人物和时装. 人物可以选择穿上帽子或穿上鞋子, 或者都穿上, 通过方法展示穿搭结果.
比较容易想到的实现方法就是单纯通过继承, 一个人物基类, 继承出一个穿帽子的人物类, 一个穿鞋子的人物类, 再一个穿帽子 + 鞋子的人物类. 在只有两种选择时, 需要产生 3 个子类, 这种实现方式每增加一种选择就要增加一倍 + 1 数量的子类, 非常不可取.
实现方式:
第一步, 抽象出一个装饰基类, 类中添加一个人物类指针, 在构造时传入人物类指针.
第二步, 增加需要修饰的同名方法, 在方法中通过指针调用原方法, 再添加新修饰内容.
第三步, 将装饰基类继承自人物基类, 为了使传入装饰类 A 进行装饰的指针能够传入装饰类 B 进行其他装饰, 并且使传入装饰类 A 的指针可以指向该装饰类对象.
最后一步, 实现装饰基类, 实现装饰内容.
备注: 为什么装饰类中增加的方法要与被装饰方法同名呢. 因为在第三步中, 为了需求, 传入装饰类的指针, 不一定指向的是人物基类对象, 也可能是另一个装饰类对象. 所以为了其他装饰类中通过指针调用的原方法存在, 对原方法装饰后的方法要与原方法同名.
优点:
可以动态为对象添加功能, 相比于继承实现, 组合的方式更加灵活而且代码量小很多
缺点:
减少了类的数量, 但是在装饰的过程中每一步都会产生一个对象, 对于 debug 来说会困难很多, 因为中间每一步产生的对象都很像.
以下是装饰模式的简单代码实现
- #ifndef DECORATOR_HPP
- #define DECORATOR_HPP
- #include <iostream>
- using namespace std;
- // 人物基类
- class Man
- {
- public:
- virtual ~Man(){}
- virtual void Show()// 用于展示
- {
- cout <<"A man." <<endl;
- }
- };
- // 装饰器抽象类
- class ManWithCloth:public Man// 继承自 Man, 为了使被装饰的对象可以传入其他装饰器进行组合装饰
- {
- public:
- ManWithCloth(Man* pMan)
- :m_pMan(pMan){}
- virtual ~ManWithCloth()
- {
- if(NULL != m_pMan)
- {
- delete m_pMan;
- m_pMan = NULL;
- }
- }
- virtual void Show()// 上述实现方式中的第二步
- {
- m_pMan->Show();// 通过指针调用原指针所指对象的方法, 然后添加方法进行修饰
- DressUp();// 对原方法增加修饰
- }
- virtual void DressUp() = 0;// 修饰方法在实现类中实现
- private:
- Man* m_pMan;
- };
- // 装饰器实现类
- class ManWearAHat:public ManWithCloth
- {
- public:
- ManWearAHat(Man* pMan)
- :ManWithCloth(pMan){}
- virtual void DressUp()
- {
- cout <<"Wear a Hat." << endl;
- }
- };
- class ManWearShoes:public ManWithCloth
- {
- public:
- ManWearShoes(Man* pMan)
- :ManWithCloth(pMan){}
- virtual void DressUp()
- {
- cout << "Wear shoes." << endl;
- }
- };
- #endif // DECORATOR_HPP
主函数中的使用
- #include <iostream>
- #include "decorator.hpp"
- using namespace std;
- int main()
- {
- Man* pMan = new Man();
- pMan->Show();
- cout <<"=====Wear Hat=====" << endl;
- pMan = new ManWearAHat(pMan);
- pMan->Show();
- cout <<"====Wear Shoes====" << endl;
- pMan = new ManWearShoes(pMan);
- pMan->Show();
- delete pMan;
- pMan = NULL;
- return 0;
- }
控制台输出结果
- A man.
- =====Wear Hat=====
- A man.
- Wear a Hat.
- ====Wear Shoes====
- A man.
- Wear a Hat.
- Wear Shoes.
如有错误, 欢迎指正
来源: http://www.jianshu.com/p/d1e4e162b5e3