工厂方法模式
根据简单工厂模式的案例可知,如果我们想要添加一种立方运算,只需要创建一个立方运算类继承运算类,然后在工厂类中添加一个case分支用于逻辑判断,问题在于,我们在进行功能扩展的同时,也修改了工厂类中的代码,这很明显违背了开放-封闭原则,于是工厂方法模式应运而生。
UML类图:
工厂模式:定义一个创建对象的工厂类,为每一种需要创建对象的类创建一个相应的具体工厂类来继承该工厂类,如有A类,B类,C类,那我们就创建3个具体工厂类继承工厂类分别用于创建A类对象、B类对象和C类对象。在客户端,根据逻辑判断出我们需要创建什么对象,先创建相应的工厂对象,然后通过相应的工厂对象调用其中的成员函数创建我们需要的对象,比如我们想要创建A类对象,就需要先创建相应的A类工厂对象,然后通过A类工厂对象调用其成员函数创建出A类对象。
#include<iostream>
using namespace std;
class Base
{
};
class A:public Base
{
};
class B:public Base
{
};
//工厂类
class Factory
{
public:
virtual Base* createConcrete() { return nullptr; };
};
//具体工厂类
class Afactory:public Factory
{
public:
Base* createConcrete() override
{
cout << "A类对象被创建" << endl;
return new A();
}
};
class Bfactory:public Factory
{
public:
Base* createConcrete()
{
cout << "B类对象被创建" << endl;
return new B();
}
};
int main()
{
//依据逻辑判断需要创建A类对象
//先创建相应的工厂对象
//如果需要更换对象,即创建B类对象,只需要把Afactory更换为Bfactory即可
Factory* factory = new Afactory();
//然后通过工厂对象调用其成员函数创建我们需要的对象
Base* base = factory->createConcrete();
}
这样,当我需要添加立方运算时,只需要添加一个立方运算类继承运算类,再添加一个相应的工厂类继承抽象工厂类,而无需对原有工厂类进行修改,这样就完全符合开放-封闭原则的精神。
但其实仔细观察就会发现,工厂模式把简单工厂内部的选择判断逻辑移到了客户端代码来进行,你想要增加功能,本来是改工厂类的,现在是要修改客户端。
优点:
工厂模式既克服了简单工厂模式违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点,使得要更换对象时,不需要大的改动就能实现,降低了客户端程序与产品对象的耦合。
缺点:
- 每增加一个产品类,就需要增加一个相应的工厂类,增加了额外的开发量。
- 将简单工厂模式中工厂类中要创建什么对象的逻辑判断移到了客户端程序,增加功能的时候需要修改客户端。
使用场景:
- 首先,工厂方法模式是new一个对象的替代品,所以在所有需要生成对象的地方都可以使用,但是需要慎重地考虑是否要增加一个工厂类进行管理,增加代码的复杂度。
- 其次,需要灵活的、可扩展的框架时,可以考虑采用工厂模式。万物皆对象,那万物也就皆产品类,例如需要设计一个连接邮件服务器的框架,有三种网络协议可供选择:POP3、IMAP、HTTP,我们就可以把这三种连接方法作为产品类,定义一个工厂类如IConnectMail,然后创建3个具体的工厂类继承工厂类用于创建3种产品类的对象,再按照不同的传入条件,创建不同的产品对象,选择不同的连接方式。如此设计,可以做到完美的扩展,如某些邮件服务器提供了WebService接口,很好,我们只要增加一个产品类和相应的工厂类就可以了。
- 再次,工厂方法模式可以用在异构项目中。