一、模式定义
子类急剧膨胀,需要重构,与Decorator一个分类。
将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立的变化。
1、最初设计
arduino
class Messager {
public:
virtual void login(string username, string password) = 0;
virtual void sendMessage(string message) = 0;
virtual void sendPicture(Image image) = 0;
virtual void playSound() = 0;
virtual void drawShape() = 0;
virtual void writeText() = 0;
virtual void connect() = 0;
virtual ~Messager() {}
};
// 平台实现
class PCMessagerBase: public Messager {
public:
virtual void playSound() {
// ...
}
virtual void drawShape() {
// ...
}
virtual void writeText() {
// ...
}
virtual void connect() {
// ...
}
};
class MobileMessagerBase: public Messager {
public:
virtual void playSound() {
// ...
}
virtual void drawShape() {
// ...
}
virtual void writeText() {
// ...
}
virtual void connect() {
// ...
}
};
// 业务抽象
class PCMessagerLite: public PCMessagerBase {
public:
virtual void login(string username, string password) {
PCMessagerBase::connect();
// ...
}
virtual void sendMessage(string message) {
PCMessagerBase::writeText();
// ...
}
virtual void sendPicture(Image image) {
PCMessagerBase::drawShape();
// ...
}
};
class PCMessagerPerfect: public PCMessagerBase {
public:
virtual void login(string username, string password) {
PCMessagerBase::playSound();
// ***
PCMessagerBase::connect();
// ...
}
virtual void sendMessage(string message) {
PCMessagerBase::playSound();
// ***
PCMessagerBase::writeText();
// ...
}
virtual void sendPicture(Image image) {
PCMessagerBase::playSound();
// ***
PCMessagerBase::drawShape();
// ...
}
};
class MobileMessagerLite: public MobileMessagerBase {
public:
virtual void login(string username, string password) {
MobileMessagerBase::connect();
// ...
}
virtual void sendMessage(string message) {
MobileMessagerBase::writeText();
// ...
}
virtual void sendPicture(Image image) {
MobileMessagerBase::drawShape();
// ...
}
};
class MobileMessagerPerfect: public MobileMessagerBase {
public:
virtual void login(string username, string password) {
MobileMessagerBase::playSound();
// ***
MobileMessagerBase::connect();
// ...
}
virtual void sendMessage(string message) {
MobileMessagerBase::playSound();
// ***
MobileMessagerBase::writeText();
// ...
}
virtual void sendPicture(Image image) {
MobileMessagerBase::playSound();
// ***
MobileMessagerBase::drawShape();
// ...
}
};
// 使用
void process() {
Messager* m = new MobileMessagerPerfect();
}
类的数目:1+n+m*n
。
2、优化方式
继承转组合。
csharp
// 业务抽象
// MobileMessagerLite与PCMessagerLite合成一个类
class MessagerLite: public Messager {
Messager* messager; // new MessagerBase();
public:
virtual void login(string username, string password) {
messager->connect();
// ...
}
virtual void sendMessage(string message) {
messager->writeText();
// ...
}
virtual void sendPicture(Image image) {
messager->drawShape();
// ...
}
};
// PCMessagerPerfect与MobileMessagerPerfect合二为一
class MessagerPerfect: public Messager {
Messager* messager;
public:
virtual void login(string username, string password) {
messager->playSound();
// ***
messager->connect();
// ...
}
virtual void sendMessage(string message) {
messager->playSound();
// ***
messager->writeText();
// ...
}
virtual void sendPicture(Image image) {
messager->playSound();
// ***
messager->drawShape();
// ...
}
};
3、解决问题
上面两个类出现之后,是有问题的。因为Messager* messager;这一行,因为他俩要是具体指定为PCMessagerBase或者MobileMessagerBase的时候,会报错。因为PCMessagerBase是纯虚类,不能实例化的。要将Messager拆分为两个类。
同时,如果两个子类有相同字段,需要提取到基类中去。
类的个数变为1 + n + m
,但是运行时候,还是有n*m
种方式。
csharp
class MessagerImp {
virtual void playSound() = 0;
virtual void drawShape() = 0;
virtual void writeText() = 0;
virtual void connect() = 0;
virtual ~MessagerImp() {}
};
class Messager {
MessagerImp* messagerImp; // new PCMessagerBase();
public:
Messager(MessagerImp* imp): messagerImp(imp) {}
virtual void login(string username, string password) = 0;
virtual void sendMessage(string message) = 0;
virtual void sendPicture(Image image) = 0;
virtual ~Messager() {}
};
// 平台实现
class PCMessagerImp: public MessagerImp {
public:
virtual void playSound() {
// ...
}
virtual void drawShape() {
// ...
}
virtual void writeText() {
// ...
}
virtual void connect() {
// ...
}
};
class MobileMessagerImp: public MessagerImp {
public:
virtual void playSound() {
// ...
}
virtual void drawShape() {
// ...
}
virtual void writeText() {
// ...
}
virtual void connect() {
// ...
}
};
// 业务抽象
class MessagerLite: public Messager {
public:
virtual void login(string username, string password) {
messagerImp->connect();
// ...
}
virtual void sendMessage(string message) {
messagerImp->writeText();
// ...
}
virtual void sendPicture(Image image) {
messagerImp->drawShape();
// ...
}
};
class MessagerPerfect: public Messager {
public:
virtual void login(string username, string password) {
messagerImp->playSound();
// ***
messagerImp->connect();
// ...
}
virtual void sendMessage(string message) {
messagerImp->playSound();
// ***
messagerImp->writeText();
// ...
}
virtual void sendPicture(Image image) {
messagerImp->playSound();
// ***
messagerImp->drawShape();
// ...
}
};
void process(){
// 运行时装配
MessagerImp* mImp = new PCMessagerImp();
Messager* m = new Messager(mImp);
}
二、杂谈
1、整理之前看过一次,整理之时毫无印象。(4年后,此视频中对此模式的讲解,会跟C++语言有一些强关联性。抽象一些与语言无关的点是,如果发现相似的继承规则需要写两套时,就可以考虑是否可以将其中的某个继承提取为一个成员变量。)
2、继承自一个纯虚基类后,如果没有重写掉所有的纯虚函数,则这个继承后的子类,依然是一个纯虚基类。
3、桥模式和装饰器模式的区别是,装饰器模式可能会存在子类的组合,而桥模式简单些,是单链,不存在组合。
4、视频链接(4年后看自己的笔记,发现只是做了搬运,于是附上视频链接):www.youtube.com/watch?v=Qci...
5、另一个比较好的博客链接:refactoringguru.cn/design-patt...