DesignPattern/02.FactoryMethod/02.FactoryMethod.md

228 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

在介绍简单工厂方法模式时Jungle总结出简单工厂模式存在最大的问题是违背了“开闭原则”每当增加新的产品时需要修改工厂类的逻辑。为了规避这种不足同时很好的利用简单工厂模式的优点本节Jungle将声情并茂地为您奉上工厂方法模式。
# 1.工厂方法模式简介
简单工厂模式中,每新增一个具体产品,就需要修改工厂类内部的判断逻辑。为了不修改工厂类,遵循开闭原则,工厂方法模式中不再使用工厂类统一创建所有的具体产品,而是针对不同的产品设计了不同的工厂,每一个工厂只生产特定的产品。
工厂方法模式定义:
```
工厂方法模式:
定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
```
## 2.工厂方法模式结构
从工厂方法模式简介中,可以知道该模式有以下几种角色:
- **抽象工厂AbstractFactory**:所有生产具体产品的工厂类的基类,提供工厂类的公共方法;
- **具体工厂ConcreteFactory**:生产具体的产品
- **抽象产品AbstractProduct**:所有产品的基类,提供产品类的公共方法
- **具体产品ConcreteProduct**:具体的产品类
工厂方法模式UML类图如下
![avatar](https://github.com/FengJungle/DesignPattern/blob/master/02.FactoryMethod/1.Picture/%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8FUML%E5%9B%BE.png)
# 3.工厂方法模式代码实例
考虑这样一个场景,如下图:
![avatar](https://github.com/FengJungle/DesignPattern/blob/master/02.FactoryMethod/1.Picture/%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F.png)
```
Jungle想要进行户外运动它可以选择打篮球、踢足球或者玩排球。和上一次的体育保管室不同这次分别由篮球保管室、足球保管室和排球保管室.
Jungle只需直接去相应的保管室就可以拿到对应的球然后Jungle就可以愉快地玩耍了。
```
对应的UML实例图如下图
![avatar](https://github.com/FengJungle/DesignPattern/blob/master/02.FactoryMethod/1.Picture/%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8FUML%E5%AE%9E%E4%BE%8B%E5%9B%BE.png)
## 3.1.定义抽象产品类AbstractSportProduct方法不提供实现
```
//抽象产品类AbstractProduct
class AbstractSportProduct
{
public:
AbstractSportProduct(){
}
virtual ~AbstractSportProduct(){}
//抽象方法:
virtual void printName() = 0;
virtual void play(){} = 0;
};
```
## 3.2.定义三个具体产品类
```
//具体产品类Basketball
class Basketball :public AbstractSportProduct
{
public:
Basketball(){
printName();
play();
}
//具体实现方法
void printName(){
printf("Jungle get Basketball\n");
}
void play(){
printf("Jungle play Basketball\n\n");
}
};
//具体产品类Football
class Football :public AbstractSportProduct
{
public:
Football(){
printName();
play();
}
//具体实现方法
void printName(){
printf("Jungle get Football\n");
}
void play(){
printf("Jungle play Football\n\n");
}
};
//具体产品类Volleyball
class Volleyball :public AbstractSportProduct
{
public:
Volleyball(){
printName();
play();
}
//具体实现方法
void printName(){
printf("Jungle get Volleyball\n");
}
void play(){
printf("Jungle play Volleyball\n\n");
}
};
```
## 3.3.定义抽象工厂类AbstractFactory方法为纯虚方法
```
//抽象工厂类
class AbstractFactory
{
public:
virtual AbstractSportProduct *getSportProduct() = 0;
virtual ~AbstractFactory(){}
};
```
## 3.4.定义三个具体工厂类
```
/具体工厂类BasketballFactory
class BasketballFactory :public AbstractFactory
{
public:
BasketballFactory(){
printf("BasketballFactory\n");
}
AbstractSportProduct *getSportProduct(){
printf("basketball");
return new Basketball();
}
};
//具体工厂类FootballFactory
class FootballFactory :public AbstractFactory
{
public:
FootballFactory(){
printf("FootballFactory\n");
}
AbstractSportProduct *getSportProduct(){
return new Football();
}
};
//具体工厂类VolleyballFactory
class VolleyballFactory :public AbstractFactory
{
public:
VolleyballFactory(){
printf("VolleyballFactory\n");
}
AbstractSportProduct *getSportProduct(){
return new Volleyball();
}
};
```
## 3.5.客户端使用方法示例
```
#include <iostream>
#include "FactoryMethod.h"
int main()
{
printf("工厂方法模式\n");
//定义工厂类对象和产品类对象
AbstractFactory *fac = nullptr;
AbstractSportProduct *product = nullptr;
fac = new BasketballFactory();
product = fac->getSportProduct();
delete fac;
fac = nullptr;
delete product;
product = nullptr;
fac = new FootballFactory();
product = fac->getSportProduct();
delete fac;
fac = nullptr;
delete product;
product = nullptr;
fac = new VolleyballFactory();
product = fac->getSportProduct();
delete fac;
fac = nullptr;
delete product;
product = nullptr;
system("pause");
return 0;
}
```
## 3.6.效果
```
工厂方法模式
BasketballFactory
basketballJungle get Basketball
Jungle play Basketball
FootballFactory
Jungle get Football
Jungle play Football
VolleyballFactory
Jungle get Volleyball
Jungle play Volleyball
```
# 4.工厂方法模式总结
如果Jungle想玩棒球Baseball只需要增加一个棒球工厂BaseballFacory然后在客户端代码中修改具体工厂类的类名而原有的类的代码无需修改。由此可看到相较简单工厂模式工厂方法模式更加符合开闭原则。工厂方法是使用频率最高的设计模式之一是很多开源框架和API类库的核心模式。
## 优点:
- 工厂方法用于创建客户所需产品,同时向客户隐藏某个具体产品类将被实例化的细节,用户只需关心所需产品对应的工厂;
- 工厂自主决定创建何种产品,并且创建过程封装在具体工厂对象内部,多态性设计是工厂方法模式的关键;
- 新加入产品时,无需修改原有代码,增强了系统的可扩展性,符合开闭原则。
## 缺点:
- 添加新产品时需要同时添加新的产品工厂,系统中类的数量成对增加,增加了系统的复杂度,更多的类需要编译和运行,增加了系统的额外开销;
- 工厂和产品都引入了抽象层客户端代码中均使用的抽象层AbstractFactory和AbstractSportProduct ),增加了系统的抽象层次和理解难度。
## 适用环境:
- 客户端不需要知道它所需要创建的对象的类;
- 抽象工厂类通过其子类来指定创建哪个对象(运用多态性设计和里氏代换原则)