简单工厂的扩展性比较差,如果要得到一个新的产品,必须修改工厂。因此,我们可以把工厂也给抽象一把,提供生产的接口,将具体生产过程放到“具体的工厂”去。
1. 功能:定义一个用于创建对象的工厂接口,让实例化类的工作在子类中完成。
2. 基本思想:在抽象父类中声明用来创建对象的方法接口,而具体子类(具体的工厂)通过覆盖接口方法实现对对象的创建过程和初始化。
3. 使用情况:
一个类不(需要)知道它所必须创建的类;
一个类希望由它的子类来指定所创建的对象;
类将创建对象的职责委托给多个帮助子类中的某一个,并希望指定某个帮助子类时。
4. 案例举例:组件对象模型(COM)中常用!
5. 结构
6.代码示例:
还是以前面的手机为例。Mobile, NokiaPhone和MotoPhone三个类没有变化。
A. 建立工厂类(Factory),注意,这个工厂是抽象的。本例中就是卖手机的柜台(Counter)。
{
public :
virtual Mobile * getPhone() {return NULL;}
virtual void returnPhone(Mobile * phone) {if (phone) delete phone;}
};
B.两个产品各自有各自的柜台
{
Mobile * getPhone() {return (new NokiaPhone());}
};
class MotoCounter : public Counter
{
Mobile * getPhone() {return (new MotoPhone());}
};
C.现在偶们的客户要买手机了:
{
Counter * nokiaCnter = new NokiaCounter();
Counter *motoCnter = new MotoCounter();
Mobile * nokia = nokiaCnter-> getPhone();
Mobile * moto = motoCnter-> getPhone();
nokia-> call();
nokia-> shortMsg();
moto-> call();
moto-> shortMsg();
// 手机坏了......
nokiaCnter-> returnPhone(nokia);
motoCnter-> returnPhone(moto);
return 0 ;
}
总结:
1, Factory Method实际上是把Simple Factory中的工厂进行抽象化,在抽象类中仅仅提供接口。具体工厂继承抽象的工厂类,根据具体的产品实现/覆盖接口。
2, 如果想要添加一个产品,只需要从抽象产品类中继承并实现一个具体的产品类,然后再对这个产品实现一个具体工厂,对原有的工厂不需要任何修改,符合“开放-封闭”原则(开放-封闭原则:软件实体(类,模块,函数等等)应该是可以扩展的,但是不可修改的)。
3, Factory Method退化后就成了Simple Factory。比如说只有一个产品工厂的情况下。
4, 不足之处在于,每个具体的产品都需要引入一个对应的工厂类。例如如果需要新增加一个商品SonyEricsson,就必须增加一个柜台SonyEricssonCnter。对于这个问题,可以采用模板方法来解决:
class CounterTemplate
{
public :
T * getPhone();
void returnPhone(T * pT);
};
template < class T >
T * CounterTemplate < T > ::getPhone()
{
return ( new T());
}
template < class T >
void CounterTemplate < T > ::returnPhone(T * pT)
{
if (pT)
delete pT;
}
// 客户端
int main()
{
cout << " Try to use template! " << endl;
CounterTemplate < NokiaPhone > nokiaFactory;
Mobile * nokia = nokiaFactory.getPhone();
nokia -> call();
nokia -> shortMsg();
CounterTemplate < MothoPhone > motoFactory;
Mobile * moto = motoFactory.getPhone();
moto -> call();
moto -> shortMsg();
// 这个地方需要把父类对象转换为子类对象,感觉有点不爽
// 希望高手们路过时,指出弊端及建议!谢谢!
nokiaFactory.returnPhone(static_cast < NokiaPhone *> (nokia));
motoFactory.returnPhone(static_cast < MotoPhone *> (moto));
return 0 ;
}