重看工厂模式
之前整个设计模式的专栏是看了李建忠老师的视频,并没有太多的自己的总结,今天来回看一下设计模式,重温设计模式的魅力
工厂模式我们介绍三个:
- 简单工厂
- 工厂方法
- 抽象工厂
简单工厂
我们举个例子,现在世界上有三场备受关注的战争。俄罗斯保护卢甘斯克和顿涅斯克独立共和国之战,加沙保卫战和果敢电诈反击战。
有战争就需要武器,这个时候他们需要枪,炮,无人机等等。他们就有了对武器的需求。
例子如下:
#include <iostream> #include <string> using namespace std; class Weapon { public: explicit Weapon(const string &name) { name_ = name; if (name == "枪") {} else if (name == "炮") {} else if (name == "飞机") {} } void useWeapon() { if (name_ == "枪") { cout << "我是枪" << endl; } else if (name_ == "炮") { cout << "我是炮" << endl; } else if (name_ == "飞机") { cout << "我是飞机" << endl; } } private: string name_; }; int main() { Weapon gun = Weapon("枪"); Weapon cannon = Weapon("炮"); Weapon plane = Weapon("飞机"); gun.useWeapon(); cannon.useWeapon(); plane.useWeapon(); return 0; }
从上面的例子中我们能看到,如果我们需要大量型号武器的话,Weapon明显会是一个巨大的类。该类设计时候存在以下的问题:
- 在Weapon中包含了很多的if elseif 代码块,整个类代码冗长,增加阅读和维护难度;并且大量的条件语句会影响系统的性能,程序执行的时候需要进行大量判断。
- Weapon职责过重,需要初始化和显示所有的武器对象,将各种武器初始化和使用放在一个类中实现,违反了单一职责原则,不利于类的维护。
- 当需要增加新型号的武器的时候,必须修改weapon代码,违反了开闭原则。
我们需要一种方式,来创建不同的武器,并且使得我们使用的时候,分的清楚,拿过来就用。以便我们更快获取战争的胜利。
- 工厂角色:即简单工厂的核心,用来创建所有的武器实例,可以被外部直接使用,创建我们需要的产品
- 抽象产品:简单工厂所有产品的父类,负责描述公共接口
- 具体产品:需要创造的具体产品
如上述的例子:我们需要一个武器工厂,使用武器工厂来生产不同的武器,则修改为如下方式:
#include <iostream> #include <string> using namespace std; class Weapon { public: virtual ~Weapon() {} virtual void useWeapon() = 0; }; class Gun : public Weapon { public: void useWeapon() override { cout << "我是枪" << endl; } }; class Cannon : public Weapon { public: void useWeapon() override { cout << "我是炮" << endl; } }; class Plane : public Weapon { public: void useWeapon() override { cout << "我是飞机" << endl; } }; class Factory { public: Weapon *createWeapon(const std::string &name) { if (name == "枪") { return new Gun; } else if (name == "炮") { return new Cannon; } else if (name == "飞机") { return new Plane; } } }; int main() { Factory ff; Weapon* weapon = nullptr; weapon = ff.createWeapon("枪"); weapon->useWeapon(); delete weapon; weapon = nullptr; weapon = ff.createWeapon("炮"); weapon->useWeapon(); delete weapon; weapon = nullptr; weapon = ff.createWeapon("飞机"); weapon->useWeapon(); delete weapon; weapon = nullptr; return 0; }
如上例子所示,我们需要生产武器种类多的时候,工厂就会变的臃肿。但是我们使用的时候,只要抽象一个武器,工厂负责生产,且生产的武器我们直接拿来使用就可以。因为工厂生产的是具体的武器,所以我们在使用的时候会用具体的武器去击败敌人。
简单工厂的优缺点也很明显了:
- 优点:实现了对象创建和使用的分离;不需要记得具体的类名称,只需要记住工厂参数即可。
- 缺点:对工厂类的依赖过重,一旦工厂类不能工作,整个系统会崩溃;增加了系统中类的个数,复杂度和理解度增加;违反开闭原则,添加新产品需要修改工厂逻辑,工厂会越来越复杂。
简单工厂适合工厂产品较少,客户端只需要告诉工厂需要生产对应的产品,对如何创建不关心的场景
工厂方法
角色和对应的职责:
- 抽象工厂:工厂方法模式的核心,任何工厂类都必须实现这个接口。
- 工厂:具体工厂是抽象工厂的一个实现,负责具体实例化产品。
- 抽象产品:工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的接口。
- 具体产品:工厂方法所创建的具体实例对象。
我们使用简单工厂生产武器的时候,工厂堆积严重,因此我们需要一个工厂调度中心,然后将武器分给不同的工厂分别生产,代码如下:
#include <iostream> #include <string> using namespace std; class Weapon { public: virtual ~Weapon() {} virtual void useWeapon() = 0; }; class Gun : public Weapon { public: void useWeapon() override { cout << "我是枪" << endl; } }; class Cannon : public Weapon { public: void useWeapon() override { cout << "我是炮" << endl; } }; class Plane : public Weapon { public: void useWeapon() override { cout << "我是飞机" << endl; } }; class AbstractFactory { public: virtual Weapon *createWeapon() = 0; }; class GunFactory : public AbstractFactory { public: Weapon *createWeapon() override { return new Gun; } }; class CannonFactory : public AbstractFactory { public: Weapon *createWeapon() override { return new Cannon; } }; class PlaneFactory : public AbstractFactory { public: Weapon *createWeapon() override { return new Plane; } }; int main() { AbstractFactory *ff = nullptr; Weapon* weapon = nullptr; ff = new GunFactory; weapon = ff->createWeapon(); weapon->useWeapon(); delete weapon; weapon = nullptr; delete ff; ff = nullptr; ff = new CannonFactory; weapon = ff->createWeapon(); weapon->useWeapon(); delete weapon; weapon = nullptr; delete ff; ff = nullptr; ff = new PlaneFactory; weapon = ff->createWeapon(); weapon->useWeapon(); delete weapon; weapon = nullptr; delete ff; ff = nullptr; return 0; }
优缺点:
- 优点:不需要记住具体的武器名字,甚至不需要对应的参数;实现了创建和使用的分离;系统扩展性变好,如果有新的武器,不需要修改原来的接口和类。
- 缺点:增加了类的数量,增加了抽象性和理解难度
工厂分类明确,职责清晰。如果我们某类型的武器不足,只需要到对应类型的工厂去取即可。
抽象工厂方法
工厂方法通过引入工厂调度中心,解决了简单工厂中工厂类职责过重的问题,但是由于工厂方法中的每个工厂只生产一类产品,导致我们工厂非常多,肯定会增加系统的开销,因此我们考虑将一些产品组成一类,使用同一个工厂生产。
比如我们在俄罗斯生产一种型号的枪炮飞机,在朝鲜生产另外一种型号的枪炮飞机,则武器供应不断,胜利就在眼前。
角色和对应的职责:
- 抽象工厂:工厂方法模式的核心,任何工厂类都必须实现这个接口。
- 工厂:具体工厂是抽象工厂的一个实现,负责具体实例化产品。
- 抽象产品:工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的接口。
- 具体产品:工厂方法所创建的具体实例对象。
#include <iostream> #include <string> using namespace std; class WeaponGun { public: virtual void useWeapon() = 0; }; class WeaponPlane { public: virtual void useWeapon() = 0; }; class WeaponCannon { public: virtual void useWeapon() = 0; }; class TMXGun : public WeaponGun { public: void useWeapon() override { cout << "使用汤姆逊" << endl; } }; class JKSGun : public WeaponGun { public: void useWeapon() override { cout << "使用捷克式" << endl; } }; class WeaponCannon1 : public WeaponCannon { public: void useWeapon() override { cout << "二营长的意大利炮" << endl; } }; class WeaponCannon2 : public WeaponCannon { public: void useWeapon() override { cout << "二营长的迫击炮" << endl; } }; class WeaponPlane1 : public WeaponPlane { public: void useWeapon() override { cout << "战斗机" << endl; } }; class WeaponPlane2 : public WeaponPlane { public: void useWeapon() override { cout << "轰炸机" << endl; } }; class AbstractFactory { public: virtual WeaponGun* createGun() = 0; virtual WeaponCannon* createCannon() = 0; virtual WeaponPlane* createPlane() = 0; }; class RussiaFactory : public AbstractFactory { public: WeaponGun* createGun() override { return new TMXGun; } WeaponCannon* createCannon() override { return new WeaponCannon1; } WeaponPlane* createPlane() override { return new WeaponPlane1; } }; class NorthKoreaFactory : public AbstractFactory { public: WeaponGun* createGun() override { return new JKSGun; } WeaponCannon* createCannon() override { return new WeaponCannon2; } WeaponPlane* createPlane() override { return new WeaponPlane2; } }; int main() { AbstractFactory *factory = nullptr; WeaponGun *gun = nullptr; WeaponCannon *cannon = nullptr; WeaponPlane *plane = nullptr; factory = new RussiaFactory; gun = factory->createGun(); cannon = factory->createCannon(); plane = factory->createPlane(); gun->useWeapon(); cannon->useWeapon(); plane->useWeapon(); delete factory; delete gun; delete cannon; delete plane; factory = new NorthKoreaFactory; gun = factory->createGun(); cannon = factory->createCannon(); plane = factory->createPlane(); gun->useWeapon(); cannon->useWeapon(); plane->useWeapon(); delete factory; delete gun; delete cannon; delete plane; return 0; }
至此,多地共同生产产品,战争胜利近在眼前。