参考:设计模式C++实现(11)——装饰模式?
1. 首先如果有一台手机,并且你一直在不停的换手机,那么可以关于手机抽象一个类(person),在用具体的手机(iphone)去继承,并通过多态转换(iphone*转person*),从而可以调用统一的抽象接口(phoneTmp->showLook()),这样无论,你换哪个手机,调用的方法(phoneTmp->showLook())都不会变,只会增加代码,不会修改代码。完美符合开闭原则。
#include <stdlib.h>
#include <iostream>
class person {
public:
virtual void showLook() = 0;
};
class iphone : public person {
public:
virtual void showLook() {
printf("iphone 裸机\r\n");
}
private:
person *mPhone;
};
int main() {
person *phoneTmp = new iphone;
phoneTmp->showLook();
}
2. 好现在买回来了手机你想给手机贴个膜。于是你的代码可能会变为下面这样。通过继承且在子类添加方法。
#include <stdlib.h>
#include <iostream>
#include <string>
class phone {
public:
virtual void showLook() = 0;
};
class iphone : public phone {
public:
iphone(std::string nm) {
name = nm;
};
virtual void showLook() {
printf("%s\r\n", name.c_str());
}
private:
phone *mPhone;
std::string name;
};
class DecorateMo : public phone {
public:
DecorateMo(phone* mp) {
mPhone1 = mp;
};
virtual void showLook() {
mPhone1->showLook();
addMo();
}
private:
phone* mPhone1;
void addMo() {
printf(" 贴膜\r\n");
};
};
int main() {
phone* tmp = new DecorateMo(new iphone("XXX的iphone"));
tmp->showLook();
}
3.这么看单独没啥问题,但过了几天你又要装个手机壳,同上,你又要去继承写一个类DecorateKe, 一样的步骤,实现出来大概是这样的。
#include <stdlib.h>
#include <iostream>
#include <string>
class person {
public:
virtual void showLook() = 0;
};
class iphone : public person {
public:
iphone(std::string nm) {
name = nm;
};
virtual void showLook() {
printf("%s ", name.c_str());
}
private:
person *mPhone;
std::string name;
};
class DecorateMo : public person {
public:
DecorateMo(person* mp) {
mPhone1 = mp;
};
virtual void showLook() {
mPhone1->showLook();
addMo();
}
private:
person* mPhone1;
void addMo() {
printf("贴膜\r\n");
};
};
class DecorateKe : public person {
public:
DecorateKe(person* mp) {
mPhone1 = mp;
};
virtual void showLook() {
mPhone1->showLook();
addKe();
}
private:
person* mPhone1;
void addKe() {
printf("装手机壳\r\n");
};
};
int main() {
person* tmp = new DecorateMo(new iphone("XXX的iphone"));
// tmp->showLook();
DecorateKe *tmp1 = new DecorateKe(tmp);
tmp1->showLook();
}
4. 所以为什么选择装饰模式,不用继承呢?
比如现在需要算配件:手机壳,膜一共需要多少钱?那么如果用现有的结构,就需要在person类加一个cost()方法,在相关类加方法,在加个全局变量,写出来大概是这样的。
#include <stdlib.h>
#include <iostream>
#include <string>
int total;
class person {
public:
virtual void showLook() = 0;
virtual void cost() {
printf("一共用了%d元\r\n", total);
};
};
class iphone : public person {
public:
iphone(std::string nm) {
name = nm;
};
virtual void showLook() {
printf("%s ", name.c_str());
}
private:
person *mPhone;
std::string name;
};
class DecorateMo : public person {
public:
DecorateMo(person* mp) {
mPhone1 = mp;
};
virtual void showLook() {
mPhone1->showLook();
addMo();
}
private:
person* mPhone1;
void addMo() {
printf("贴膜\r\n");
cost();
};
virtual void cost() {
total += 20;
printf("20\r\n");
}
};
class DecorateKe : public person {
public:
DecorateKe(person* mp) {
mPhone1 = mp;
};
virtual void showLook() {
mPhone1->showLook();
addKe();
}
private:
person* mPhone1;
void addKe() {
printf("装手机壳\r\n");
cost();
};
virtual void cost() {
total += 30;
printf("30\r\n");
}
};
int main() {
person *tmpPhone = new iphone("XXX的iphone");
person *tmp = new DecorateMo(tmpPhone);
// tmp->showLook();
person *tmp1 = new DecorateKe(tmp);
tmp1->showLook();
tmpPhone->cost();
}
5.?或许有其他办法,但没有可以不修改person类的办法实现这个功能。。因为很多东西继承peson,改动person如果逻辑复杂了,会带来新风险,这样很不好,我们希望哪个person类不要被修改,所以装饰模式的作用就体现出来了。
装饰模式的优点:就是便于扩展,并且不修改基类。且扩展性非常好,不用修改任何原有代码。
那么用装饰模式怎么增加cost功能呢?首先加个抽象的Decorate类,但为了保持之前的showLook()方法,我们需要用Decorate类继承person类。
- 感觉区别不是很大,但不修改person类会直接做到对person类和他的子类的BUG的0输入。。
- 并且这种模式可以增加任意的新功能,且可以保持不修改之前的person类相关代码,这个特性完全符合了开闭思想,降低风险的引入。
#include <stdlib.h>
#include <iostream>
#include <string>
int total;
class person {
public:
virtual void showLook() = 0;
};
class iphone : public person {
public:
iphone(std::string nm) {
name = nm;
};
virtual void showLook() {
printf("%s\r\n", name.c_str());
}
private:
person *mPhone;
std::string name;
};
class Decorate : public person{
public:
virtual void cost() {
printf("total = %d\r\n", total);
};
virtual void showLook() = 0;
};
class DecorateMo : public Decorate {
public:
DecorateMo(person* mp) {
mPhone1 = mp;
};
virtual void showLook() {
addMo();
}
void costTotal() { Decorate::cost(); }
private:
person* mPhone1;
void addMo() {
printf("贴膜\r\n");
cost();
};
virtual void cost() {
total += 20;
printf("20\r\n");
}
};
class DecorateKe : public Decorate {
public:
DecorateKe(person* mp) {
mPhone1 = mp;
};
virtual void showLook() {
addKe();
}
void costTotal() {Decorate::cost(); }
private:
person* mPhone1;
void addKe() {
printf("装手机壳\r\n");
cost();
};
virtual void cost() {
total += 30;
printf("30\r\n");
}
};
int main() {
person *tmpPhone = new iphone("XXX的iphone");
tmpPhone->showLook();
DecorateMo *tmp = new DecorateMo(tmpPhone);
tmp->showLook();
tmp->costTotal();
person *tmp1 = dynamic_cast<person *>(tmp);
DecorateKe *tmp2 = new DecorateKe(tmp1);
tmp2->showLook();
tmp2->costTotal();
}
总结: 装饰者模式适用于:新增加的功能点,在不改变现有的子类,父类的前提下,抽象一个接口类(Decarate),说白了,为了不改变原有的基类,加了一个中间人Decarate去继承Person,这样新加的功能,与之前的代码完全解耦。所以当需要新加一个功能点的时候,考虑用装饰者模式吧。
|