工厂模式

工厂模式的简介

工厂模式属于创建型模式,提供了一种创建对象的最佳方式。

在工厂模式中,创建对象时不会对客户端暴露创建逻辑,而是通过一个共同的接口来指向新创建的对象。

工厂模式的实现方式可分为简单工厂模式、工厂方法模式、抽象工厂模式,每个实现方法都存在优点和缺点。

以鞋厂为例,对各实现方式进行介绍。

深入浅出工厂模式(基础篇)

简单工厂模式

场景:

  • 鞋厂可以指定生产耐克、阿迪达斯和李宁的鞋子。哪个鞋好卖,老板就生产哪个,看形势生产。

结构组成:

  1. 工厂类(ShoesFactory):工厂模式的核心类,会定义一个用于创建指定的具体实例对象的接口
  2. 抽象产品类(Shoes):是具体产品类继承的父类或实现的接口
  3. 具体产品类(NikeShoes\AdidasShoes\LiNingShoes):工厂类所创建的对象就是具体产品类的实例

代码

  • Shoes为鞋子的抽象类(基类),接口函数为Show(),用于显示鞋子广告
  • NikeShoesAdiadasShoesLiNingShoes为具体鞋子的类,它们都继承于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;
}
}
};
  • main函数
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

特点

  • 工厂类封装了创建具体产品对象的函数

缺点

  • 拓展性很差,新增产品时,需要修改工厂类

适用范围

工厂类负责创建的对象比较少,客户只知道传入了工厂类的参数,对于如何创建对象(逻辑)不关心。

工厂方法模式

场景

  • 各类鞋子炒的非常火热,为了大量生产每种类型的鞋子,要针对不同品牌的鞋子开设独立的生产线,那么每个生产线就只能生产同类型品牌的鞋。

结构组成

  1. 抽象工厂类(ShoesFactory):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现
  2. 具体工厂类(NikeProducer\AdidasProducer\LiNingProducer):继承于抽象工厂,实现创建对应具体产品对象的方法。
  3. 抽象产品类(Shoes):具体产品继承的父类
  4. 具体产品类(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;
}

特点

  • 工厂方法模式抽象出了工厂类,提供创建具体产品的接口,交由子类去实现
  • 工厂方法模式的应用并不只是为了封装具体产品对象的创建,而是要把具体产品对象的创建放到具体工厂类实现
  • 完全遵循开闭原则,实现了可拓展和更复杂的层次结构,明确了职责

缺点

  • 每新增一个产品,就要增加一个对应产品的具体工厂类,相比简单工厂模式而言,工厂方法模式需要更多的类定义
  • 一条生产线只能生产一个产品

适用范围

当系统需要经常增加新产品,不希望修改现有代码时,工厂方法模式特别合适。

抽象工厂模式

场景

  • 鞋厂为了扩大业务,不仅生产鞋子,还把运动品牌的衣服也一起生产了

结构组成(和工厂方法模式一样)

  1. 抽象工厂类(ShoesFactory):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现
  2. 具体工厂类(NikeProducer):继承于抽象工厂,实现创建对应具体产品对象的方式
  3. 抽象产品类(Shoes\Clothes):是具体产品继承的父类
  4. 具体产品类(NikeShoes\NikeClothes):具体工厂所创建的对象

代码

  • ClothesShoes,分别为衣服和鞋子的抽象产品类
  • NikeClothesNikeShoes,分别是耐克衣服和鞋子的具体产品类
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和相应的具体工厂类

适用范围

  • 抽象工厂为你提供了一个接口, 可用于创建每个系列产品的对象。 只要代码通过该接口创建对象, 那么你就不会生成与应用程序已生成的产品类型不一致的产品

深入浅出工厂模式(进阶篇)

上述三种工厂模式,在新增产品时,要么需要修改工厂类,要么需要新增具体的工厂类,封装性不足。

为了进一步提升工厂类的封装性,达到新增产品时,不需要修改工厂类,也不需要新增具体的工厂类的目的,引入以下两种方法。

模板工厂

将工厂方法模式封装成模板工厂类,这样在新增产品时,不需要新增具体的工厂类,减少了代码的编写量。

模板工厂代码

  • ShoesClothes,分别为鞋子和衣服的抽象类
  • NikeShoesUniqloClothes,分别为耐克鞋子和优衣库衣服具体产品类
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是产品抽象类,如ShoesClothes
  • ConcreteFactory为具体模板工厂类,其中模版参数AbstactProduct_t是产品抽象类,如Shoes、Clothes;ConcreteProduct_t是产品具体类,如NikeShoesUniqloClothes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
* 抽象模板工厂
* 模板参数:AbstractProduct_t是产品抽象类
* */
template <class AbstractProduct_t>
class AbstractFactory {
public:
virtual AbstractProduct_t *CreateProduct() = 0;
virtual ~AbstractFactory() {}
};

/*
* 具体模板工厂类
* 模板参数:AbstractProduct_t产品抽象类,ConcreteProduct_t产品具体类
* */
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
/* 基类 产品注册模板接口类
* 模板参数:ProductType_t表示产品抽象类
* */
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 &);
};

/* 工厂模板类,用于获取注册产品对象
* 模板参数:ProductType_t表示产品抽象类
* */
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;
}

// 根据产品名name,获取对应的具体产品对象
ProductType_t *GetProduct(std::string name) {
// 从map中知道啊已经注册过的产品,并返回产品对象
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 &);

// 保存注册过的产品,key为产品名,value为产品类型
std::map<std::string, IProductRegistrar<ProductType_t> *> m_ProductRegistrar;
}

/*
* 产品注册模版类,用于创建具体产品和从工厂里注册产品
* 模版参数:ProductType_t为产品抽象类,ProductImpl_t表示产品具体类
* */
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()
{
// ========================== 生产耐克球鞋过程 ===========================//
// 注册产品种类为Shoes(基类),产品为NiKe(子类)到工厂,产品名为nike
ProductRegistrar<Shoes, NiKeShoes> nikeShoes("nike");
// 从工厂获取产品种类为Shoes,名称为nike的产品对象
Shoes *pNiKeShoes = ProductFactory<Shoes>::Instance().GetProduct("nike");
// 显示产品的广告语
pNiKeShoes->Show();
// 释放资源
if (pNiKeShoes)
{
delete pNiKeShoes;
}

// ========================== 生产优衣库衣服过程 ===========================//
// 注册产品种类为Clothe(基类),产品为UniqloClothe(子类)到工厂,产品名为uniqlo
ProductRegistrar<Clothe, UniqloClothe> adidasShoes("uniqlo");
// 从工厂获取产品种类为Shoes,名称为adidas的产品对象
Clothe *pUniqloClothe = ProductFactory<Clothe>::Instance().GetProduct("uniqlo");
// 显示产品的广告语
pUniqloClothe->Show();
// 释放资源
if (pUniqloClothe)
{
delete pUniqloClothe;
}

return 0;
}

参考

C++深入浅出工厂模式

C++深入浅出工厂模式(进阶篇)


工厂模式
https://delta0406.github.io/2025/09/01/技术/设计模式/工厂模式/
作者
执妄
发布于
2025年9月1日
许可协议