245 lines
7.8 KiB
Markdown
245 lines
7.8 KiB
Markdown
回顾之前的设计模式,简单工厂模式所有逻辑都封装在工厂类中,工厂根据客户提供的产品名字创建对应产品的对象实例;工厂方法模式将产品的创建过程放到了具体工厂类中,每一个工厂可以创建一个具体产品,由此可能会创建许多工厂类。很多时候,**一个工厂不只是生产一种产品,而是生产一类产品**,比如一个体育用品工厂,可以生产篮球、足球、排球等多种产品。此时我们可以把这些相关的产品归纳为一个“产品族”,由同一个工厂来生产,这即是Jungle今天要学习的抽象工厂模式。
|
||
|
||
# 1.抽象工厂模式简介
|
||
抽象工厂模式是常用的创建型设计模式之一。而今天Jungle要学习的抽象工厂模式,其抽象程度更高,每一个具体工厂可以生产一组相关的具体产品对象。
|
||
|
||
抽象工厂模式定义:
|
||
```
|
||
抽象工厂模式:
|
||
|
||
提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
|
||
```
|
||
简言之,一个工厂可以提供创建多种相关产品的接口,而无需像工厂方法一样,为每一个产品都提供一个具体工厂。
|
||
|
||
# 2.抽象工厂模式结构
|
||
抽象工厂模式结构与工厂方法模式结构类似,不同之处在于,一个具体工厂可以生产多种同类相关的产品:
|
||
|
||
- **抽象工厂(AbstractFactory)**:所有生产具体产品的工厂类的基类,提供工厂类的公共方法;
|
||
- **具体工厂(ConcreteFactory)**:生产具体的产品
|
||
- **抽象产品(AbstractProduct)**:所有产品的基类,提供产品类的公共方法
|
||
- **具体产品(ConcreteProduct)**:具体的产品类
|
||
抽象工厂模式UML类图如下:
|
||
![avatar](https://github.com/FengJungle/DesignPattern/blob/master/03.AbstractFactory/1.Picture/%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8FUML%E5%9B%BE.png)
|
||
|
||
结合抽象工厂模式定义和UML,可以看到具体工厂ConcreteFactory_A可以生产两种产品,分别是ConcreteProduct_A_1和ConcreteProduct_A_2,另一个具体工厂ConcreteFactory_B同理。客户端使用时,需要声明一个抽象工厂*AbstractFactory*和两个抽象产品*AbstractProduct*。
|
||
|
||
# 3.抽象工厂模式代码实例
|
||
考虑这样一个场景,如下图:
|
||
![avatar](https://github.com/FengJungle/DesignPattern/blob/master/03.AbstractFactory/1.Picture/%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F%E5%AE%9E%E4%BE%8B%E5%9B%BE.png)
|
||
|
||
```
|
||
Jungle想要进行户外运动,它可以选择打篮球和踢足球。
|
||
但这次Jungle不想弄脏原本穿的T恤,所以Jungle还需要穿球衣,打篮球就穿篮球衣,踢足球就穿足球衣。
|
||
篮球保管室可以提供篮球和篮球衣,足球保管室可以提供足球和足球衣。
|
||
Jungle只要根据心情去某个保管室,就可以换上球衣、拿上球,然后就可以愉快地玩耍了。
|
||
```
|
||
对应的UML实例图如下图:
|
||
![avatar](https://github.com/FengJungle/DesignPattern/blob/master/03.AbstractFactory/1.Picture/%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8FUML%E5%AE%9E%E4%BE%8B%E5%9B%BE.png)
|
||
|
||
|
||
|
||
## 3.1.定义产品类
|
||
### 3.1.1.产品类Ball
|
||
- 抽象产品类AbstractBall, 球类的基类,定义抽象方法play
|
||
```
|
||
//抽象产品类AbstractBall
|
||
class AbstractBall
|
||
{
|
||
public:
|
||
AbstractBall(){}
|
||
//抽象方法:
|
||
virtual void play() = 0;
|
||
virtual ~AbstractBall() {}
|
||
};
|
||
```
|
||
- 具体产品类, 分别为Basketball和Football,具体实现方法play
|
||
```
|
||
//具体产品类Basketball
|
||
class Basketball :public AbstractBall
|
||
{
|
||
public:
|
||
Basketball(){
|
||
play();
|
||
}
|
||
//具体实现方法
|
||
void play(){
|
||
printf("Jungle play Basketball\n\n");
|
||
}
|
||
};
|
||
|
||
//具体产品类Football
|
||
class Football :public AbstractBall
|
||
{
|
||
public:
|
||
Football(){
|
||
play();
|
||
}
|
||
//具体实现方法
|
||
void play(){
|
||
printf("Jungle play Football\n\n");
|
||
}
|
||
};
|
||
```
|
||
|
||
### 3.1.2.产品类Shirt
|
||
- 抽象产品类AbstractShirt:球衣类的基类,定义抽象方法wearShirt
|
||
```
|
||
//抽象产品类AbstractShirt
|
||
class AbstractShirt
|
||
{
|
||
public:
|
||
AbstractShirt(){}
|
||
//抽象方法:
|
||
virtual void wearShirt() = 0;
|
||
virtual ~AbstractShirt(){}
|
||
};
|
||
```
|
||
- 具体产品类BasketballShirt和FootballShirt,具体实现方法wearShirt
|
||
```
|
||
//具体产品类BasketballShirt
|
||
class BasketballShirt :public AbstractShirt
|
||
{
|
||
public:
|
||
BasketballShirt(){
|
||
wearShirt();
|
||
}
|
||
//具体实现方法
|
||
void wearShirt(){
|
||
printf("Jungle wear Basketball Shirt\n\n");
|
||
}
|
||
};
|
||
|
||
//具体产品类FootballShirt
|
||
class FootballShirt :public AbstractShirt
|
||
{
|
||
public:
|
||
FootballShirt(){
|
||
wearShirt();
|
||
}
|
||
//具体实现方法
|
||
void wearShirt(){
|
||
printf("Jungle wear Football Shirt\n\n");
|
||
}
|
||
};
|
||
```
|
||
|
||
## 3.2.定义工厂类
|
||
- 定义抽象工厂AbstractFactory,声明两个方法getBall和getShirt
|
||
```
|
||
//抽象工厂类
|
||
class AbstractFactory
|
||
{
|
||
public:
|
||
virtual AbstractBall *getBall() = 0;
|
||
virtual AbstractShirt *getShirt() = 0;
|
||
virtual ~AbstractFactory(){}
|
||
};
|
||
```
|
||
- 定义具体工厂BasketballFactory和FootballFactory,重新具体实现两个方法getBall和getShirt
|
||
```
|
||
//具体工厂类BasketballFactory
|
||
class BasketballFactory :public AbstractFactory
|
||
{
|
||
public:
|
||
BasketballFactory(){
|
||
printf("BasketballFactory\n");
|
||
}
|
||
AbstractBall *getBall(){
|
||
printf("Jungle get basketball\n");
|
||
return new Basketball();
|
||
}
|
||
AbstractShirt *getShirt(){
|
||
printf("Jungle get basketball shirt\n");
|
||
return new BasketballShirt();
|
||
}
|
||
};
|
||
|
||
//具体工厂类BasketballFactory
|
||
class FootballFactory :public AbstractFactory
|
||
{
|
||
public:
|
||
FootballFactory(){
|
||
printf("FootballFactory\n");
|
||
}
|
||
AbstractBall *getBall(){
|
||
printf("Jungle get football\n");
|
||
return new Football();
|
||
}
|
||
AbstractShirt *getShirt(){
|
||
printf("Jungle get football shirt\n");
|
||
return new FootballShirt();
|
||
}
|
||
};
|
||
```
|
||
|
||
## 3.3.客户端使用方法示例
|
||
```
|
||
#include <iostream>
|
||
#include "AbstractFactory.h"
|
||
|
||
int main()
|
||
{
|
||
printf("抽象工厂模式\n");
|
||
|
||
//定义工厂类对象和产品类对象
|
||
AbstractFactory *fac = nullptr;
|
||
AbstractBall *ball = nullptr;
|
||
AbstractShirt *shirt = nullptr;
|
||
|
||
fac = new BasketballFactory();
|
||
ball = fac->getBall();
|
||
shirt = fac->getShirt();
|
||
delete ball;
|
||
ball = nullptr;
|
||
delete shirt;
|
||
shirt = nullptr;
|
||
delete fac;
|
||
fac = nullptr;
|
||
|
||
fac = new FootballFactory();
|
||
ball = fac->getBall();
|
||
shirt = fac->getShirt();
|
||
delete ball;
|
||
ball = nullptr;
|
||
delete shirt;
|
||
shirt = nullptr;
|
||
delete fac;
|
||
fac = nullptr;
|
||
|
||
system("pause");
|
||
return 0;
|
||
}
|
||
```
|
||
## 3.4.效果
|
||
```
|
||
抽象工厂模式
|
||
BasketballFactory
|
||
Jungle get basketball
|
||
Jungle play Basketball
|
||
|
||
Jungle get basketball shirt
|
||
Jungle wear Basketball Shirt
|
||
|
||
FootballFactory
|
||
Jungle get football
|
||
Jungle play Football
|
||
|
||
Jungle get football shirt
|
||
Jungle wear Football Shirt
|
||
```
|
||
|
||
# 4.抽象工厂模式总结
|
||
抽象工厂模式中,如果需要新增加一个系列的产品,比如足球系列,只需增加一族新的具体产品类(抽象和具体)并提供一个对应的工厂类即可。但是,如果要在已有的产品族里增加另一个产品,比如Jungle打篮球,除了需要篮球和篮球衣外,**Jungle还想换双篮球鞋**,这时候该怎么办呢?是不是要去修改BasketballFactory呢?由此,Jungle总结了抽象工厂模式的特点:
|
||
|
||
## 优点:
|
||
|
||
- 工厂方法用于创建客户所需产品,同时向客户隐藏某个具体产品类将被实例化的细节,用户只需关心所需产品对应的工厂;
|
||
- 新加入产品系列时,无需修改原有系统,增强了系统的可扩展性,符合开闭原则。
|
||
## 缺点:
|
||
|
||
- 在已有产品系列中添加新产品时需要修改抽象层代码,对原有系统改动较大,违背开闭原则
|
||
## 适用环境:
|
||
|
||
- 一系列/一族产品需要被同时使用时,适合使用抽象工厂模式;
|
||
- 产品结构稳定,设计完成之后不会向系统中新增或剔除某个产品
|