工厂模式的简介
工厂模式属于创建型模式,提供了一种创建对象的最佳方式。
在工厂模式中,创建对象时不会对客户端暴露创建逻辑,而是通过一个共同的接口来指向新创建的对象。
工厂模式的实现方式可分为简单工厂模式、工厂方法模式、抽象工厂模式,每个实现方法都存在优点和缺点。
以鞋厂为例,对各实现方式进行介绍。
深入浅出工厂模式(基础篇)
简单工厂模式
场景:
- 鞋厂可以指定生产耐克、阿迪达斯和李宁的鞋子。哪个鞋好卖,老板就生产哪个,看形势生产。
结构组成:
- 工厂类(ShoesFactory):工厂模式的核心类,会定义一个用于创建指定的具体实例对象的接口
- 抽象产品类(Shoes):是具体产品类继承的父类或实现的接口
- 具体产品类(NikeShoes\AdidasShoes\LiNingShoes):工厂类所创建的对象就是具体产品类的实例
代码
- Shoes为鞋子的抽象类(基类),接口函数为Show(),用于显示鞋子广告
- NikeShoes、AdiadasShoes、LiNingShoes为具体鞋子的类,它们都继承于Shoes抽象类
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
| class Shoes { pubic: virtual ~Shoes() {} virtual void Show() = 0; }
class NikeShoes : public Shoes { public: void Show() { std::cout << "我是耐克鞋,我的广告语: Just do it" << std::endl; } }
class AdidasShoes : public Shoes { public: void Show() { std::cout << "我是阿迪达斯球鞋,我的广告语:Impossible is nothing" << std::endl; } };
class LiNingShoes : public Shoes { public: void Show() { std::cout << "我是李宁球鞋,我的广告语:Everything is possible" << std::endl; } };
|
- ShoesFactory为工程类,类里实现根据鞋子类型创建对应鞋子产品对象的**CreateShoes(SHOES_TYPE type)**函数
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
| enum SHOES_TYPE { NIKE, LINING, ADIDAS };
class ShoesFactory { public: Shoes *CreateShoes(SHOES_TYPE type) { switch (type) { case NIKE: return new NikeShoes(); break; case LINING: return new LiNingShoes(); break; case ADIDAS: return new AdidasShoes(); break; default: return NULL; break; } } };
|
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
| int main() { ShoesFactory shoesFactory; Shoes *pNikeShoes = shoesFactory.CreateShoes(NIKE); if (pNikeShoes != NULL) { pNikeShoes->show(); delete pNikeShoes; pNikeShoes = NULL; } Shoes *pLiNingShoes = shoesFactory.CreateShoes(LINING); if (pLiNingShoes != NULL) { pLiNingShoes->Show();
delete pLiNingShoes; pLiNingShoes = NULL; }
Shoes *pAdidasShoes = shoesFactory.CreateShoes(ADIDAS); if (pAdidasShoes != NULL) { pAdidasShoes->Show();
delete pAdidasShoes; pAdidasShoes = NULL; } }
|
s
特点
缺点
适用范围
工厂类负责创建的对象比较少,客户只知道传入了工厂类的参数,对于如何创建对象(逻辑)不关心。
工厂方法模式
场景
- 各类鞋子炒的非常火热,为了大量生产每种类型的鞋子,要针对不同品牌的鞋子开设独立的生产线,那么每个生产线就只能生产同类型品牌的鞋。
结构组成
- 抽象工厂类(ShoesFactory):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现
- 具体工厂类(NikeProducer\AdidasProducer\LiNingProducer):继承于抽象工厂,实现创建对应具体产品对象的方法。
- 抽象产品类(Shoes):具体产品继承的父类
- 具体产品类(NikeShoes\AdidasShoes\LiNingShoes):具体工厂所创建的对象
代码
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
| * **ShoesFactory**抽象工厂类,提供了创建具体鞋子产品的纯虚函数 * **NikeProducer**、**AdidasProducer**、**LiNingProducer**具体工厂类,继承抽象工厂类,实现对应鞋子产品对象的创建
class ShoesFactory { public: virtual Shoes *CreateShoes() = 0; virtual ~ShoesFactory() {} };
class NikeProducer : public ShoesFactory { public: Shoes *CreateShoes() { return new NikeShoes(); } };
class AdidasProducer : public ShoesFactory { public: Shoes *CreateShoes() { return new AdidasShoes(); } };
class LiNingProducer : public ShoesFactory { public: Shoes *CreateShoes() { return new LiNingShoes(); } };
|
- main函数,针对每种类型的鞋子,构造每种类型的生产线,再由各个生产线生产出对应的鞋子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int main() { ShoesFactory *nikeProducer = new NikeProducer(); Shoes *nikeShoes = nikeProducer->CreateShoes(); nikeShoes->Show(); delete nikeShoes; delete nikeProducer; ShoesFactory *adidasProducer = new AdidasProducer(); Shoes *adidasShoes = adidasProducer->CreateShoes(); adidasShoes->Show(); delete adidasShoes; delete adidasProducer;
return 0; }
|
特点
- 工厂方法模式抽象出了工厂类,提供创建具体产品的接口,交由子类去实现
- 工厂方法模式的应用并不只是为了封装具体产品对象的创建,而是要把具体产品对象的创建放到具体工厂类实现
- 完全遵循开闭原则,实现了可拓展和更复杂的层次结构,明确了职责
缺点
- 每新增一个产品,就要增加一个对应产品的具体工厂类,相比简单工厂模式而言,工厂方法模式需要更多的类定义
- 一条生产线只能生产一个产品
适用范围
当系统需要经常增加新产品,不希望修改现有代码时,工厂方法模式特别合适。
抽象工厂模式
场景
- 鞋厂为了扩大业务,不仅生产鞋子,还把运动品牌的衣服也一起生产了
结构组成(和工厂方法模式一样)
- 抽象工厂类(ShoesFactory):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现
- 具体工厂类(NikeProducer):继承于抽象工厂,实现创建对应具体产品对象的方式
- 抽象产品类(Shoes\Clothes):是具体产品继承的父类
- 具体产品类(NikeShoes\NikeClothes):具体工厂所创建的对象
代码
- Clothes和Shoes,分别为衣服和鞋子的抽象产品类
- NikeClothes和NikeShoes,分别是耐克衣服和鞋子的具体产品类
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
| class Clothes { public: virtual void Show() = 0; virtual ~Clothes() {} };
class NikeClothes : public Clothes { public: void show() { std::cout << "我是耐克衣服,时尚我最在行!" << std::endl; } };
class Shoes { public: virtual void Show() = 0; virtual ~Shoes() {} };
class NikeShoes : public Shoes { public: void Show() { std::cout << "我是耐克鞋子,让你酷起来!" << std::endl; } };
|
- Factory为抽象工厂,提供了创建鞋子**CreateShoes()和衣服产品CreateClothes()**对象的接口
- NikeProducer为具体工厂,实现了创建耐克鞋子和耐克衣服的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Class Factory { public: virtual Shoes *CreateShoes() = 0; virtual Clothes *CreateClothes() = 0; virtual ~Factory() {} };
class NikeProducer : public Factory { public: Shoes *CreateShoes() { return new NikeShoes(); } Clothes *CreateClothes() { return new NikeClothes(); } }
|
- main函数,构造耐克工厂对象,通过耐克工厂对象再创建耐克产品族的衣服和鞋子对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| int main() { Factory *nikeProducer = new NikeProducer(); Shoes *nikeShoes = nikeProducer->CreateShoes(); Clothes *nikeClothes = nikeProducer->CreateClothes(); nikeShoes->show(); nikeClothes->show(); delete nikeShoes; delete nikeClothes; delete nikeProducer; return 0; }
|
特点
- 提供了一个接口,可以创建多个产品族中的产品对象。如创建耐克工厂,则可以创建耐克鞋子产品、衣服产品等
- 可以减少工厂方法中工厂类数量
缺点
- 同工厂方法模式一样,新增产品时,都需要增加一个对应产品的具体工厂类
- 因为分组,所以分组中产品扩展比较困难,例如新增一个球拍产品,则需要改动抽象工厂Factory和相应的具体工厂类
适用范围
- 抽象工厂为你提供了一个接口, 可用于创建每个系列产品的对象。 只要代码通过该接口创建对象, 那么你就不会生成与应用程序已生成的产品类型不一致的产品
深入浅出工厂模式(进阶篇)
上述三种工厂模式,在新增产品时,要么需要修改工厂类,要么需要新增具体的工厂类,封装性不足。
为了进一步提升工厂类的封装性,达到新增产品时,不需要修改工厂类,也不需要新增具体的工厂类的目的,引入以下两种方法。
模板工厂
将工厂方法模式封装成模板工厂类,这样在新增产品时,不需要新增具体的工厂类,减少了代码的编写量。
模板工厂代码
- Shoes和Clothes,分别为鞋子和衣服的抽象类
- NikeShoes和UniqloClothes,分别为耐克鞋子和优衣库衣服具体产品类
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
| class Shoes { public: virtual void show() = 0; virtual ~Shoes() {} };
class NikeShoes : public Shoes { public: void Show() { std::cout << "我是耐克球鞋,我的广告语:Just do it" << std::endl; } };
class Clothes { public: virtual void Show() = 0; virtual ~Clothes() {} };
class UniqloClothes : public Clothes { public: void Show() { std::cout << "我是优衣库衣服,我的广告语:I am Uniqlo" << std::endl; } }
|
- AbstractFactory为抽象模板工厂类,其中模版参数AbstractProduct_t是产品抽象类,如Shoes、Clothes
- ConcreteFactory为具体模板工厂类,其中模版参数AbstactProduct_t是产品抽象类,如Shoes、Clothes;ConcreteProduct_t是产品具体类,如NikeShoes、UniqloClothes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
template <class AbstractProduct_t> class AbstractFactory { public: virtual AbstractProduct_t *CreateProduct() = 0; virtual ~AbstractFactory() {} };
template <class AbstractProdut_t, class ConcreteProduct_t> class ConcreteFactory : public AbstractFactory<AbstractProduct_t> { public: AbstractProduct_t *CreateProduct() { return new ConcreteProduct_t(); } }
|
- main函数,根据不同类型的产品,构造对应产品的工厂对象,并通过对应产品的工厂对象创建具体的产品对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| int main() { ConcreteFactory<Shoes, NikeShoes> nikeFactory; Shoes *pNikeShoes = nikeFactory.CreateProduct(); pNikeShoes->Show(); ConcreteFactory<Clothes, UniqloClothes> uniqloFactory; Clothes *pUniqloClothes = uniqloFactory.CreateProduct(); pUniqloClothtes->Show(); delete pNikeShoes; pNikeShoes = NULL; delete pUniqloClothes; pUniqloClothes = NULL; return 0; }
|
产品注册模版类+单例工厂模版类
模板工厂缺少一个可以统一随时随地获取指定产品对象的类,因此可以将产品注册的对象用std::map保存,通过key-value的方式可以轻松获取对应的产品对象实例。具体实现思路为:
- 把产品注册的功能封装成产品注册模版类。注册的产品对象保存在工厂模版类的std::map,便于产品对象的获取
- 把获取产品对象的功能封装成工厂模板类,为了能随时随地获取指定产品对象,把工厂设计成单例模式
代码
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
|
template <class ProductType_t> class IProductRegistrar { public: virtual ProductType_t *CreateProduct() = 0; protected: IProductRegistrar() {} virtual ~IProductRegistrar() {} private: IProductRegistrar(const IProductRegistrar &); const IProductRegistrar &operator=(const IProductRegistrar &); };
template <class ProductType_t> class ProductFactory { public: static ProductFactory<ProductType_t> &Instance() { static ProductFactory<ProductType_t> instance; return instance; } void RegisterProduct(IProductRegistrar<ProductType_t> *registrar, std::string name) { m_ProductRegistrar[name] = registrar; } ProductType_t *GetProduct(std::string name) { if (m_ProductResgistrar.find(name) != m_ProductResgistrar.end()) { return m_ProductRegistrar[name]->CreateProduct(); } std::cout << "No product found for " << name << std::endl; return NULL; } private: ProductFactory() {} ~ProductFactory() {} ProductFactory(const ProductFactory &); const ProductFactory &operator=(const ProductFactory &); std::map<std::string, IProductRegistrar<ProductType_t> *> m_ProductRegistrar; }
template <class ProductType_t, class ProductImpl_t> class ProductRegistrar : public IProductRegistrar<ProductType_t> { public: explicit ProductRegistrar(std::string name) { ProductFactory<ProductType_t>::Instance().RegisterProduct(this, name); }
ProductType_t *CreateProduct() { return new ProductImpl_t(); } };
|
- main函数通过ProductRegistrar注册不同类型的产品,再统一由ProductFactory单例工厂获取指定的产品对象
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
| int main() { ProductRegistrar<Shoes, NiKeShoes> nikeShoes("nike"); Shoes *pNiKeShoes = ProductFactory<Shoes>::Instance().GetProduct("nike"); pNiKeShoes->Show(); if (pNiKeShoes) { delete pNiKeShoes; }
ProductRegistrar<Clothe, UniqloClothe> adidasShoes("uniqlo"); Clothe *pUniqloClothe = ProductFactory<Clothe>::Instance().GetProduct("uniqlo"); pUniqloClothe->Show(); if (pUniqloClothe) { delete pUniqloClothe; }
return 0; }
|
参考
C++深入浅出工厂模式
C++深入浅出工厂模式(进阶篇)