目录
工厂模式也是平时我们编程用的比较多的一种行为设计模式,它提供了一种创建对象的最佳方式。工厂模式提供了一种创建对象的方式,而无需指定要创建的具体类。工厂模式属于创建型模式,它在创建对象时提供了一种封装机制,将实际创建对象的代码与使用代码分离。
工厂模式创建对象(参数化的工厂),UML类图如下:
工厂模式包含以下几个核心角色:
备注:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
抽象车类和具体车类如下:Car.h
#include <iostream>
#include <assert.h>
//抽象对象"车"
class ICar
{
public:
virtual ~ICar() {}
virtual void run() = 0;
virtual bool isNull() = 0;
};
//对象适配器
class CCarAdapter : public ICar
{
public:
void run() override {
assert(0);
}
bool isNull() override {
return false;
}
};
//空对象模式实现
class CNullCar : public ICar
{
public:
void run() override {
assert(0);
}
bool isNull() override {
return true;
}
};
//宝马车
class CBmwCar : public CCarAdapter
{
public:
void run() override {
std::cout << "Bmw car is running...\n";
}
};
//吉利车
class CJiliCar : public CCarAdapter
{
public:
void run() override {
std::cout << "Jili car is running...\n";
}
};
//大众车
class CDazhongCar : public CCarAdapter
{
public:
void run() override {
std::cout << "Dazhong car is running...\n";
}
};
//保时捷豪车
class CPorscheCar : public CCarAdapter
{
public:
void run() override {
std::cout << "Porsche car is running...\n";
}
};
//长安车
class CChangAnCar : public CCarAdapter
{
public:
explicit CChangAnCar(int n) :m_n(n) {
}
void run() override {
std::cout << "ChangAn " << m_n << " cars is running...\n";
}
private:
int m_n;
};
参数化工厂:CarFactory.h
#include "Car.h"
#include <memory>
enum CarType
{
eBMWCar = 0, //宝马车
eJILICar, // 吉利车
eDAZHONGCar, // 大众车
eCHANGANCar, //长安车
ePORSCHECar, //保时捷
};
class CCarFactory
{
public:
//[1]
ICar* create(int type) {
std::unique_ptr<ICar> temp;
switch (type) {
case eBMWCar:
temp.reset(new CBmwCar());
break;
case eJILICar:
temp.reset(new CJiliCar());
break;
case eDAZHONGCar:
temp.reset(new CDazhongCar());
break;
case ePORSCHECar:
temp.reset(new CPorscheCar());
break;
default:
//assert(0);
temp.reset(new CNullCar());
break;
}
return temp.release();
}
};
测试代码:
#include <iostream>
#include "Car.h"
#include "CarFactory.h"
int main()
{
std::unique_ptr<ICar> pCar;
std::unique_ptr<CCarFactory> factory(new CCarFactory());
//[1]
std::cout << "Car Factory mode1:\n";
pCar.reset(factory->create(eBMWCar)); //宝马
pCar->run();
pCar.reset(factory->create(eDAZHONGCar)); //大众
pCar->run();
pCar.reset(factory->create(eJILICar)); //吉利
pCar->run();
pCar.reset(factory->create(11)); //不生产这种车
if (pCar->isNull()) {
std::cout << "Carfactory not product the 11 type car!!!\n";
}
pCar.reset(factory->create(ePORSCHECar)); //保时捷
pCar->run();
return 0;
}
输出:
优点:
1) 良好的时装性,代码结构清晰。一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或约束字符串)就可以了,不用知道包建对象的艰辛过程,降低模块间的耦合。
2) 工厂方法模式的扩展性非常优秀。在增加产品类的情况下,只要适当地修改具体的工厂类或扩展一个工厂类,就可以完成拥抱变化。
3) 屏蔽产品类。这一特点非常重要,产品类的实现如何变化,调用者都不需要关心,它只需要关心产品的接口,只要接口保持不变,系统中的上层模块就不要发生变化。因为产品类的实例化工作是由工厂类负责的,一个产品对象具体由哪一个产品生成是由工厂类决定的。在数据库开发中,大家应该能够深刻体会到工厂方法模式的好处:如果使用DBC连接数据库,数据库从MysQL切换到Oracle,需要改动的地方就是切换一下驱动名称(前提条件是SOL语包是标准语句),其他的都不需要修改,这是工厂方法模式灵活性的一个直接案例。
4) 工厂方法模式是典型的解耦框架。高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪采特法则,我不需要的就不要去交流:也符合依赖倒置原则,只依赖产品类的抽象;当然也符合单氏替换原则,使用产品子类替换产品父类,没问题。
缺点:
1) 增加代码复杂度:引入工厂模式会增加代码的复杂度,因为需要定义工厂类来管理对象的创建,同时还需要考虑如何处理异常和错误情况。
2) 违反开闭原则:开闭原则是指软件实体应该对扩展开放,对修改封闭。然而,工厂模式在一定程度上违反了这一原则,因为它在编译时确定了类的结构和关系,导致对新的类结构不适应,难以扩展和维护。
3) 不易调试:由于工厂模式将对象创建的逻辑封装在工厂类中,当出现错误或异常时,调试可能会变得更加困难,因为问题可能出现在隐藏的工厂类中。