最初的解决方案:
class PizzaStore
{
public:
Pizza *orderPizza(string type){
Pizza *pizza;
/* comment_1:由于要不断有新的类型的pizza产生,这段代码要经常修改 */
if (type == aaa) {
pizza = new aaa;
} else if (type == bbb) {
pizza = new bbb;
}
else {
// ...
}
/* comment_1 */
pizza->bake();
pizza->cut();
pizza->box();
return pizza;
}
};
下面用工厂模式来处理:
1. 简单工厂
把经常需要变动的那部分封装
/* 封装用的类,封装变化的部分 */
class SimplePizzaFactory
{
Pizza *createPizza(string type) {
Pizza pizza;
/* 上面comment_1注释的都搬到这里来 */
return pizza;
}
};
/* 新的解决方案 */
class PizzaStore
{
public:
PizzaStore() {
simplePizzaFactory = new SimplePizzaFactory;
}
Pizza *orderPizza(string type) {
Pizza *pizza = simplePizzaFactory->createPizza(type);
pizza->bake();
pizza->cut();
pizza->box();
return pizza;
}
private:
SimplePizzaFactory *simplePizzaFactory;
};
2. 工厂方法
简单的工厂造成的一个问题是生产出来的pizza没有多样性,都是一模一样,下面看工厂方法的解决方案。
/* 工厂方法的解决方案 */
class PizzaStore
{
public:
Pizza *orderPizza(string type) {
Pizza *pizza = createPizza(type);
pizza->bake();
pizza->cut();
pizza->box();
return pizza;
}
protected:
/* createPizza方法期待继承者自己实现,随便什么类型 */
virtual Pizza *createPizza(string type) = 0;
};
工厂方法可以做到的是:假如有ABCD四种pizza,不同的PizzaStore继承者所生产的Pizza都会在这四种里选择。
有的时候虽然都是A,可是有的要刷辣酱,而有的要刷甜酱,怎么办?也就是说A的“酱”这个属性值是不一样的!有没有必要建立一个“酱”的抽象对象呢,然后它派生出了“辣酱”和“甜酱”?有必要!整个结构就变成下面这样了(引出抽象工厂):
3. 抽象工厂
父类:原料P、原料Q、原料R、原料S
子类:P1, P2, P3, Q1, Q2, Q3, Q4, R1, R2, R3, S1, S2
父类:Pizza
子类:Pizza A(P, Q)、Pizza B(P, Q, R)、Pizza C(P, S)、Pizza D(Q, R, S)
注意:每种Pizza有的属性并不一定完全相同,有的Pizza要加酱,而有的不要加。现在我们又需要一个工厂,来生产PQRS原料。
/* 生产原料的抽象工厂 */
class IngredientFactory
{
public:
P *createP() = 0;
Q *createQ() = 0;
R *createR() = 0;
S *createS() = 0;
};
由上面这个抽象类我们就可以派生出各种各样的原料工厂了,足以满足Pizza A(P, Q)、Pizza B(P, Q, R)、Pizza C(P, S)、Pizza D(Q, R, S)的需求了。
注意:虽然Pizza A只需要PQ两种原料,针对A的原料工厂也不能只实现createP和createQ,否则这个工厂仍旧是个抽象工厂(c++的特性)。
PizzaStore的接口要这样写了:
/* 新的PizzaStore,无非就是多了一个原料工厂的属性,用以决定本工厂具体使用哪种PQRS */
class PizzaStore
{
public:
PizzaStore(IngredientFactory f) {
ingredientFactory = f;
}
Pizza *orderPizza(string type) {
Pizza *pizza = createPizza(type);
pizza->bake();
pizza->cut();
pizza->box();
return pizza;
}
protected:
virtual Pizza *createPizza(string type) = 0;
IngredientFactory ingredientFactory;
};
PizzaStore的继承者应该这样实现createPizza了:
/* PizzaStore的子类,具体的PizzaStore */
Pizza *createPizza(string type) {
Pizza *pizza;
if (type == A) {
pizza = new PizzaA(ingredientFactory);
}
else if (type == B) {
pizza = new PizzaB(ingredientFactory);
}
else {
// ...
}
};
Pizza类应该这样写了:
/* 新的Pizza类 */
class Pizza
{
public:
Pizza() {
p=0; q=0; r=0; s=0;
}
private:
P p; Q q; R r; S s;
};
/* Pizza的继承者 */
class PizzaA : public Pizza
{
public:
PizzaA(IngredientFactory f) {
p = f.createP();
q = f.createQ();
/* 看上面,A类Pizza只有PQ两种原料 */
}
};