设计模式——builder
对于创建型的问题,有一类问题不像工厂模式那样,面对一系列的产品,而是一个部分整体的关系。
比如造一个车,需要造发动机,轮胎,方向盘,车门,车窗,车灯,后备箱... 等等很多部分,电脑需要内存条件,芯片,键盘,鼠标,显示器,磁盘等等部件。
创建一个整体需要不同的部分。
但是每个部分是可以扩展,更换的,比如电脑的显示屏,不变的部分是,一台电脑总是基本上需要这些部件。
这种创建一个整体,但是部分的创建细节保留变化的问题,通常可以使用一种叫做 builder的设计模式来对付
Seperate the construction of a complex object from its represemtation so that the same construction process can create different representation.
将复杂对象的构造与其表示分离,以便相同的构造过程可以创建不同的表示。
这句话一般不太容易读懂。有时候我甚至更愿意看代码。
构造,表示,分离... 很多大佬谈到设计模式的时候,常常有类似的词汇蹦出来。
我们要知道它是指代什么?
构造指的是一套逻辑动作,比如先做什么后做什么,表示,则是实现这些动作。
开头组装电脑,汽车的例子就是如此,我们知道一台电脑要若干个大件,先组装芯片 内存,显示器,是为构造,用什么牌子和规格的部件可以视为表示,当然实际问题中,所有的部件构造的细节都是“表示”需要关心的。
对于分离,耦合,通常没有编写过面向对象的程序员会不明所以。
分离是怎么样分离。
设计模式中所讲的分离,大概就是实现和接口可以独立变化,或者更具体一点,这里有虚函数,对于 java语言来说这里有 interface,可以 override的接口。
当你把一个动作声明为 虚函数接口,实际上,它就做到了所谓的分离了?
为什么会这样?
class A
{
public:
virtual void move() = 0;
}
/*
client 代码,出现在某个上下文中
*/
A * p = new A();
p->move(); // p 到底是 A 的哪个派生类,在运行时决定
我们要改 move的动作,
派生 A,重新实现 move 的内部,这样client 的代码不会变化,说明接口和实现“分离”了,达到了各自变化扩展不影响的效果。
这种所谓的“分离”给代码维护带来很多可观的好处。
回到 builder 模式。
实现builder模式一般需要一个“导演”——把它当做是一个知道建造过程的角色,但是他不关心每个部分的构建细节。
代码代码概要
#include <list>
#include <iostream>
class Builder {
public:
virtual void build() = 0;
};
class Computer;
class Director
{
public:
void registerBuilder(Builder *builder) {
m_builders.push_back(builder);
}
void construct() {
for (Builder* builder: m_builders) {
builder->build();
}
return ;
}
private:
std::list<Builder*> m_builders;
};
class MouseBuilder: public Builder
{
public:
void build() {
std::cout << "build mouse" << std::endl;
}
};
class MonitorBuilder: public Builder
{
public:
void build() {
std::cout << "build monitor" << std::endl;
}
};
int main(int argc, char *argv[])
{
MonitorBuilder monitorBuilder;
MouseBuilder mouseBuilder;
Director d;
d.registerBuilder(&monitorBuilder);
d.registerBuilder(&mouseBuilder);
d.construct();
return 0;
}
导演类,视情况,可以做成一个单例。builder模式一般是对于步骤比较固定的创建型问题,比如固定的五个部分,所以上面的代码的持有 builder的方式可以不是用list,也可以用映射 map,或者直接持有每个builder的句柄。
这样的代码,扩展维护的时候,一般只是修改每个具体的builder的内部接口,对于Director及调用 Director的上下文,则不需要变更。
看起来很不错。