//说些废话
已经有一个多月没写博客了,读书节买了一大堆书看,老“码”识途这本书好好玩,讲的好多机器语言啊汇编啊的知识,对理解框架有很好的作用,比较喜欢,还在钻研,本来想看完那一大堆书再写博客的,然后想了想,25本书,起码得一年才看得完,设计模式这么重要又不能一年后再写,不然都忘光了。然后翻了翻之前写的设计模式,果然自己写的博客才印象深刻,看一眼就记得自己用的什么例子和实现的要点在哪里,所以,还是坚持一下写博客吧。
话说,这个模式好烦,最起码四个类,然后其间的逻辑关系也是烦,理解后要用我觉得还是得慢慢想好类怎么构建的好,不然估计要写出一坨...
//部分资料来源
1.C++设计模式:http://www.jellythink.com/archives/98
2.程杰——大话设计模式
//正文
先来简单说说上面四个类各自的用途和各类之间的关系:
1.Man类:其实这个才是我们要用的那个东西,其他都是为了建造这个Man的。这个类就简单理解成我们最后要生成的产品。
2.Builder类:这个是个虚类,有什么用呢?就是用于对Man类进行一些更改操作的类的父类,提供了虚拟方法供重写。这个类内并不需要包含Man类成员。
3.FatManBuilder类、ThinManBuilder类:这个就是用于更改Man类操作的实用类,重写了Builder类提供的方法。这个类内需要包含要更改的Man类成员。
4.Director类:这个就是指挥类,用于指挥构建产品,其实就是指挥FatManBuilder / ThinManBuilder 的函数调用顺序。这个类内需要包含Builer类。
然后来看看我的代码:
#include <QCoreApplication>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Noodle
{
public:
void Add(const string info)
{
NoodleVec.push_back(info);
}
void show()
{
for(vector<string>::iterator item = NoodleVec.begin();
item != NoodleVec.end();item++)
{
cout<<*item<<" ";
}
cout<<"noodle";
}
private:
vector<string> NoodleVec;
};
class Chief
{
public:
virtual void meat(){}
virtual void noodle(){}
virtual void egg(){}
virtual void salt(){}
virtual Noodle *getNoodle(){return nullptr;}
};
class AChief:public Chief
{
public:
AChief(){MyNoodle = new Noodle();}
void meat(){MyNoodle->Add("beef");}
void noodle(){MyNoodle->Add("shrimp noodles");}
void egg(){MyNoodle->Add("chicken egg");}
void salt(){MyNoodle->Add("salt");}
Noodle *getNoodle(){return MyNoodle;}
private:
Noodle *MyNoodle;
};
class BChief:public Chief
{
public:
BChief(){MyNoodle = new Noodle();}
void meat(){MyNoodle->Add("pork");}
void noodle(){MyNoodle->Add("bamboo noodles");}
void egg(){MyNoodle->Add("duck egg");}
void salt(){MyNoodle->Add("salt");}
Noodle *getNoodle(){return MyNoodle;}
private:
Noodle *MyNoodle;
};
class Director
{
public:
Director(Chief *temp){TheChief = temp;}
void CreateNoodle()
{
TheChief->meat();
TheChief->noodle();
TheChief->egg();
TheChief->salt();
}
private:
Chief *TheChief;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Chief *chiefA = new AChief();
Director *director = new Director(chiefA);
director->CreateNoodle();
Noodle *NoodleObj = chiefA->getNoodle();
if(NoodleObj == nullptr)
return 0;
NoodleObj->show();
return a.exec();
}
然后放个运行的截图吧:
那么解释一下:
1.Noodle类就是UML图中的Man类,是我们要做的面。
2.Chief类,就是Builder类,这提供了做面的抽象方法,加肉、加面、加蛋、加盐。
3.AChief类、BChief类,这个就是子类啦,这个提供了做面的具体方法,例如加什么肉?牛肉、猪肉?加什么面?虾子面、竹竿面?加什么蛋?鸡蛋、鸭蛋?
就好像我的AChief类一样,是牛肉、虾子面、鸡蛋、盐。
然而BChief类,是猪肉、竹竿面、鸭蛋、盐。(这个不知道能不能食)
这样做就可以实现了需要建造的东西步骤一样,但具体的东西属性上有一点点差别。
4.Director类,上面那行说的建造的东西步骤一样,这里就是体现,这个类就是调用Chief类的方法的,想要什么顺序就什么顺序,你现在先加肉,再加面,再加蛋,再加盐。
万一厨房来了个新主管,他说我做面要先放盐,再加面,再加蛋,再加肉。(这只是举例,现实中这样的面好可怕!)
这样的话,我们只需要新建一个Director类,然后在实现中把Chief类中的方法调用顺序改改就行了。
这个就是建造者模式的好处
使得建造代码(Chief)与表示代码(Noodle)分离,由于建造者隐藏了该产品是如何组装(Director)的,所以若需要一个产品的内部表示,只需要再定义一个具体的建造者(AChief / BChief)就可以了
建造者模式:主要是用于创建一些复杂的对象(Noodle),这些对象内部构建间的建造顺序(Director)通常是稳定的,但对象内部的构建(AChief / BChief)通常面临复杂的变化。
那么说就说清楚了。
//问题
1.
Q:什么时候用建造者模式?
A: 当你要建造的东西内部(属性)建造顺序基本上是稳定的,然后具体建造的东西有区别。
简单来说就是,你要按一个特定的流程去建造只有一点点不同的产品的时候就用。
举例子来说就是,你麦当劳和肯德鸡,都是用一样的机器去做个汉堡,这个机器已经有了确立的顺序,先加菜、再加肉、再夹上面包。但是加原料有不同,例如你是加番茄酱还是芝士酱?生菜还是芽菜?
2.
Q:区分一下其他模式?
A:唔,这个虽然说得不知道准确不,不过按自己理解吧。
简单工厂、工厂方法,这是为了隐藏类构造,不搭边。
策略模式,这个我当时理解它就是多态,除了Context维护之外,其他就跟建造者模式Builder和其子类重写方法的作用一样了。
SOLID原则,这个模式满足所有。
装饰模式,这个不搭边吧。这个是为了扩展的。防止类爆炸。
代理模式,就我举例那个牛油面包,没啥关系。
原型模式,这个是那个为了克隆然后讨论了一大堆深浅拷贝的模式,没关系。
模板方法模式,这个倒是有一点点关系,虽然模板方法模式是把逻辑骨架写在父类中,提供一些相应的抽象方法供子类重写,这个跟建造者有点像,因为建造者是把逻辑骨架放到director里面,然后builder提供虚方法给子类重写。那么我们不禁发问,为啥建造者模式要特别地把逻辑骨架放在一个独立的director类中呢?这是因为,建造者模式本来就是有保护表现的时候顺序会改变,就是说,你如果把逻辑骨架放到builder里面,那万一厨房真换了主管,先加盐的,那你就有改写builder类的逻辑骨架了,违反了开放-封闭原则对吧?除此之外,子类重写虚方法,实现部分属性不同这些都是一样的。还算相似吧。
迪米特法则,这个是为了不要类暴露的,第三方调用,不搭边。
外观模式,这个嘛,有一点点像吧,你可以理解成,director的方法就是一个facade,然后别人去调用这个facade就得到一个产品了,不过,外观模式压根就不改子系统的具体实现,所以,只能说一点带你关系,真的只有一点点。