1. 简单工厂模式的弊端
在上一节简单工厂模式中,创建了一个工厂类,用于生产需要的对象,但是这种方式有一个弊端,它违反了设计模式中的开放-封闭原则,先来看相关的代码:
// 恶魔果实工厂类
enum class Type:char{SHEEP, LION, BAT};
class SmileFactory
{
public:SmileFactory() {}~SmileFactory() {}AbstractSmile* createSmile(Type type){AbstractSmile* ptr = nullptr;switch (type){case Type::SHEEP:ptr = new SheepSmile;break;case Type::LION:ptr = new LionSmile;break;case Type::BAT:ptr = new BatSmile;break;default:break;}return ptr;}
};
在上面的工厂函数中需要生成三种人造恶魔果实,现在如果想要生成更多,那么就需要在工厂函数的switch
语句中添加更多的case
,很明显这违背了封闭
原则,也就意味着需要基于开放
原则来解决这个问题。
使用工厂模式可以很完美的解决上述的问题,简单工厂模式是只有一个工厂类,而工厂模式是有很多的工厂类:
- 一个基类,包含一个虚工厂函数,用于实现多态。
- 多个子类,重写父类的工厂函数。每个子工厂类负责生产一种恶魔果实,这相当于再次解耦,将工厂类的职责再次拆分、细化,如果要生产新品种的恶魔果实,那么只需要添加对应的工厂类,无需修改原有的代码。
2. 工厂模式
我们先修改一下简单工厂模式中工厂类相关的代码:
// 恶魔果实工厂类
class AbstractFactory
{
public:virtual AbstractSmile* createSmile() = 0;virtual ~AbstractFactory() {}
};class SheepFactory : public AbstractFactory
{
public:AbstractSmile* createSmile() override{return new SheepSmile;}~SheepFactory(){cout << "释放 SheepFactory 类相关的内存资源" << endl;}
};class LionFactory : public AbstractFactory
{
public:AbstractSmile* createSmile() override{return new LionSmile;}~LionFactory(){cout << "释放 LionFactory 类相关的内存资源" << endl;}};class BatFactory : public AbstractFactory
{
public:AbstractSmile* createSmile() override{return new BatSmile;}~BatFactory(){cout << "释放 BatFactory 类相关的内存资源" << endl;}
};
通过示例代码可以看到,每个工厂类其实都不复杂,在每个子工厂类中也只是重写了父类的工厂方法而已,每个子工厂类生产一种恶魔果实,但是工厂函数的返回值确是恶魔果实类的基类类型,相当于是使用父类指针指向了子类对象,此处也是用到了多态
。通过这样的处理,工厂函数也就不再需要参数了。
根据简单工厂模式的代码和上面的修改就可以把工厂模式的UML类图画出来了:
完整的代码应该是这样的:
#include <iostream>
using namespace std;class AbstractSmile
{
public:virtual void transform() = 0;virtual void ability() = 0;virtual ~AbstractSmile() {}
};
// 人造恶魔果实· 绵羊形态
class SheepSmile : public AbstractSmile
{
public:void transform() override{cout << "变成人兽 -- 山羊人形态..." << endl;}void ability() override{cout << "将手臂变成绵羊角的招式 -- 巨羊角" << endl;}
};// 人造恶魔果实· 狮子形态
class LionSmile : public AbstractSmile
{
public:void transform() override{cout << "变成人兽 -- 狮子人形态..." << endl;}void ability() override{cout << "火遁· 豪火球之术..." << endl;}
};class BatSmile : public AbstractSmile
{
public:void transform() override{cout << "变成人兽 -- 蝙蝠人形态..." << endl;}void ability() override{cout << "声纳引箭之万剑归宗..." << endl;}
};// 恶魔果实工厂类
class AbstractFactory
{
public:virtual AbstractSmile* createSmile() = 0;virtual ~AbstractFactory() {}
};class SheepFactory : public AbstractFactory
{
public:AbstractSmile* createSmile() override{return new SheepSmile;}~SheepFactory(){cout << "释放 SheepFactory 类相关的内存资源" << endl;}
};class LionFactory : public AbstractFactory
{
public:// 工厂函数AbstractSmile* createSmile() override{return new LionSmile;}~LionFactory(){cout << "释放 LionFactory 类相关的内存资源" << endl;}};class BatFactory : public AbstractFactory
{
public:// 工厂函数AbstractSmile* createSmile() override{return new BatSmile;}~BatFactory(){cout << "释放 BatFactory 类相关的内存资源" << endl;}
};int main()
{AbstractFactory* factory = new BatFactory;AbstractSmile* obj = factory->createSmile();obj->transform();obj->ability();return 0;
}
在main()
函数中的这句代码是实例化了一个生成蝙蝠恶魔果实的工厂对象:
AbstractFactory* factory = new BatFactory;
在真实的项目场景中,要生成什么类型的恶魔果实其实是通过客户端的操作界面控制的,它对应的可能是一个按钮或者是一个选择列表,用户做出了选择,程序就可以根据该需求去创建对应的工厂对象,最终将选择的恶魔果实生产出来。
在上面的例子中,不论是恶魔果实的基类,还是工厂类的基类,它们的虚函数可以是纯虚函数,也可以是非纯虚函数。这样的基类在设计模式中就可以称之为抽象类(此处的抽象类和C++中对抽象类的定义有一点出入)。