设计模式设计模式工厂模式 - 人造恶魔果实工厂2
苏丙榅
配套视频课程已更新完毕,大家可通过以下两种方式观看视频讲解:
关注公众号:爱编程的大丙,或者进入大丙课堂学习。
1. 简单工厂模式的弊端
在上一节简单工厂模式中,创建了一个工厂类,用于生产需要的对象,但是这种方式有一个弊端,它违反了设计模式中的开放-封闭原则,先来看相关的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| 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. 工厂模式
我们先修改一下简单工厂模式中工厂类相关的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| 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类图画出来了:
完整的代码应该是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| #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()
函数中的这句代码是实例化了一个生成蝙蝠恶魔果实的工厂对象:
1
| AbstractFactory* factory = new BatFactory;
|
在真实的项目场景中,要生成什么类型的恶魔果实其实是通过客户端的操作界面控制的,它对应的可能是一个按钮或者是一个选择列表,用户做出了选择,程序就可以根据该需求去创建对应的工厂对象,最终将选择的恶魔果实生产出来。
在上面的例子中,不论是恶魔果实的基类,还是工厂类的基类,它们的虚函数可以是纯虚函数,也可以是非纯虚函数。这样的基类在设计模式中就可以称之为抽象类(此处的抽象类和C++中对抽象类的定义有一点出入)。