工厂模式(创建型)
前言
上一篇简要介绍了OOD的设计原则及设计模式的基本概念,从本篇开始介绍包括创建型(5)&结构型(7)&行为型(11)总共23种基本的设计模式和简单的C++代码实现。本篇介绍工厂模式,包括以下三种模式:
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
简单工厂模式
在介绍工厂方法模式之前,先介绍下简单工厂模式
意图
定义一个创建对象的工厂类,并提供相应的创建对象的接口,简单工厂模式并不把一个类的实例化延迟到子类(也不存在子类)
参与者
Concrete Factory
提供创建对象的接口,可以使用一个create接口来进行硬编码,也可以针对不同具体产品提供不同的create接口Abstract Product
抽象产品类,可以派生出多个具体产品Concrete Product
具体产品类
模式结构
代码实现
首先定义一个抽象产品类,只提供一个简单的
Show()
接口显示不同产品类型的打印:1
2
3
4
5class AbstractProduct
{
public:
virtual void Show() = 0;
};然后分别根据抽象产品派生两个不同的产品类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class ProductA: public AbstractProduct
{
public:
void Show()
{
cout << "I am Product A" << endl;
}
};
class ProductB: public AbstractProduct
{
public:
void Show()
{
cout << "I am Product B" << endl;
}
};最后定义一个简单的工厂类,并提供一个静态的create方法,通过硬编码的方法来创建对象:
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
34class SimpleFactory
{
public:
static AbstractProduct* CreateProduct(int ProductType)
{
switch (ProductType)
{
case 1:
return new ProductA();
break;
case 2:
return new ProductB();
break;
default:
return NULL;
break;
}
}
};
//除了硬编码还可以通过根据不同的产品提供不同create接口来实现:
class SimpleFactory
{
public:
static AbstractProduct* CreateProductA()
{
return new ProductA();
}
static AbstractProduct* CreateProductB()
{
return new ProductB();
}
};测试简单工厂:
1
2
3
4
5
6
7
8
9
10
11
12void SimpleFactoryTest()
{
AbstractProduct *pPA = SimpleFactory::CreateProduct(1);
// AbstractProduct *pPA = SimpleFactory::CreateProductA;
pPA->Show();
AbstractProduct *pPB = SimpleFactory::CreateProduct(2);
// AbstractProduct *pPA = SimpleFactory::CreateProductB;
pPB->Show();
delete pPA; pPA = NULL;
delete pPB; pPB = NULL;
};
运行结果:
I am Product A
I am Product B
适用场景
比较简单的对象创建
优缺点
- 优点:简单
- 缺点:要增加新的产品类型时,就需要修改工厂类,这就违反了开放封闭原则
工厂方法模式
如果想在增加新的产品类型时候,不需要修改原来的工厂类,从而符合开放封闭原则,可以考虑使用工厂方法模式类定义一个抽象接口,并增加新的产品工厂类即可
意图
定义一个用于创建对象的接口让子类决定实例化哪一个类。工厂模式使一个类的实例化延迟到其子类
参与者
Abstract Factory
声明工厂方法,该方法返回一个Abstract Product类型的对象。Abstract Factory也可以定义一个工厂方法的缺省实现,它返回一个缺省的Concrete Product对象;
工厂接口是工厂方法模式的核心,与调用者直接交互用来提供产品Concrete Factory
Concrete Factory决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现;
重定义工厂方法以返回一个Concrete Product实例;Abstract Product
抽象产品类,可以派生出多个具体产品Concrete Product
具体产品类
模式结构
代码实现
抽象产品和具体的产品代码见上节的简单工厂模式的代码实现部分
与简单工厂模式不同的是,新增加了个抽象工厂类,提供一个virtual的create产品方法:
1
2
3
4
5class AbstractFactory
{
public:
virtual AbstractProduct* CreateProduct() = 0;
};然后针对不同的具体产品,定义不同的具体工厂类,并override抽象工厂的create产品方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// 产品类A的具体工厂A
class FactoryA: public AbstractFactory
{
public:
AbstractProduct* CreateProduct()
{
return new ProductA();
}
};
// 产品类B的具体工厂B
class FactoryB: public AbstractFactory
{
public:
AbstractProduct* CreateProduct()
{
return new ProductB();
}
};测试工厂方法模式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15void FactoryMethodTest()
{
AbstractFactory *pFA = new FactoryA(); // 抽象的工厂指针指向具体的工厂对象
AbstractProduct *pPA = pFA->CreateProduct(); // 抽象的产品指针具体的产品对象
pPA->Show();
AbstractFactory *pFB = new FactoryB();
AbstractProduct *pPB= pFB->CreateProduct();
pPB->Show();
delete pFA; pFA = NULL;
delete pPA; pPA = NULL;
delete pFB; pFB = NULL;
delete pPB; pPB = NULL;
}
运行结果:
I am Product A
I am Product B
使用场景
- 当一个类不知道它所必须创建的对象的类的时候
- 当一个类希望由它的子类来指定它所创建的对象的时候
- 工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。
假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度 - 需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装
优缺点
- 优点:
- 可以使代码结构清晰,有效地封装变化。在编程中,产品类的实例化有时候是比较复杂和多变的,通过工厂模式,将产品的实例化封装起来,使得调用者根本无需关心产品的实例化过程,
只需依赖工厂即可得到自己想要的产品 - 对调用者屏蔽具体的产品类。如果使用工厂模式,调用者只关心产品的接口就可以了,至于具体的实现,调用者根本无需关心。
- 降低耦合度。产品类的实例化通常来说是很复杂的,它需要依赖很多的类,而这些类对于调用者来说根本无需知道,如果使用了工厂方法,我们需要做的仅仅是实例化好产品类,然后交给调用者使用。对调用者来说,产品所依赖的类都是透明的,即使变更了具体的实现,对调用者来说没有任何影响
- 可以使代码结构清晰,有效地封装变化。在编程中,产品类的实例化有时候是比较复杂和多变的,通过工厂模式,将产品的实例化封装起来,使得调用者根本无需关心产品的实例化过程,
- 缺点:
新增加一个产品类型就需要引入一个工厂类,会增加系统的复杂度
抽象工厂模式
意图
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
参与者
- Abstract Factory
声明工厂方法,声明一个创建抽象产品对象的操作接口,通常含有多个创建接口对应于不同的产品族
所谓的产品族(也称为产品系列),是指位于不同产品等级结构中功能相关联的产品组成的家族,在编程中,通常一个产品结构,表现为一个接口或者抽象类
Concrete Factory
Concrete Factory决定如何实例化产品,是实现扩展的途径,一般而言,多少种产品系列就有多少个具体工厂
重定义工厂方法以返回一个Concrete Product实例;Abstract Product
抽象产品类,可以派生出多个具体产品Concrete Product
具体产品类
模式结构
代码实现
1.抽象产品A(对应一个产品结构)
1 | class AbstractProductA |
2.抽象产品A派生的具体产品A1,A2
1 | class ProductA1 : public AbstractProductA |
3.抽象产品B(对应第二个产品结构)
1 | class AbstractProductB |
4.抽象产品B派生的具体产品B1,B2
1 | class ProductB1: public AbstractProductB |
5.抽象工厂,包括创建多个不同的产品等级的抽象接口,此类的产品等级分别为A,B
1 | class AbstractFactoryAB |
6.具体工厂,包含具体工厂1和工厂2,分别生成产品族1(A1,B1)和产品族2(A2,B2)
1 | class Factory1: public AbstractFactoryAB |
7.测试抽象工厂模式:
1 | void AbstractFactoryTest() |
运行结果:
I am Product A1
I am Prouduct B1
I am Product A2
I am Prouduct B2
使用场景
当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。
假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点。
优缺点
- 优点:
抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。产品族一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理 - 缺点:
产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的
简单工厂模式&工厂方法模式&抽象工厂模式的区别
- 此三者目的都是为了使一个系统独立于它的产品的创建、组合过程
- 简单工厂模式一般只提供一个具体的工厂,没有抽象的工厂;而工厂方法模式&抽象工厂模式提供了抽象的工厂,更符合开闭原则
- 抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象
- 工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构
- 工厂方法模式所提供的具体产品是衍生自一个等级结构(接口或抽象类);抽象工厂模式所提供的具体产品则是衍生自不同的等级结构(接口或抽象类)