Design/factoryMethod/readme.md
2024-10-28 14:07:29 +08:00

178 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
* @Description:
* @version:
* @Author: 莫邪
* @Date: 2023-10-08 14:38:14
* @LastEditors: 莫邪
* @LastEditTime: 2023-10-08 15:32:06
-->
# 工厂方法模式
一般情况下工厂模式分为三种更加细分的类型简单工厂、工厂方法和抽象工厂。在GoF的《设计模式》一书中它将简单工厂模式看作是工厂方法模式的一种特例所以工厂模式只被分成了工厂方法和抽象工厂两类。实际上前面一种分类方法更加常见.
## 介绍
简单工厂每次增加一个产品都需要修改工厂代码内部的逻辑, 为了遵循**开闭原则**, 工厂方法将不在使用一个工厂统一进行所有产品的生产, 而是每一个产品都由一个工厂进行生产.
## 定义
- **抽象工厂AbstractFactory**:所有生产具体产品的工厂类的基类,提供工厂类的公共方法;
- **具体工厂ConcreteFactory**:生产具体的产品
- **抽象产品AbstractProduct**:所有产品的基类,提供产品类的公共方法
- **具体产品ConcreteProduct**:具体的产品类
## 流程
- 定义抽象产品类, 不提供实现方法
```cpp
class AbstractProduct { //抽象产品
public:
AbstractProduct() {}
virtual void print() = 0;
virtual void play() = 0;
};
```
- 定义三个具体产品类
```cpp
class PowerArmor : public AbstractProduct {
public:
PowerArmor() {
print();
play();
}
void print() {
std::cout << "得到一个动力装甲" << std::endl;
}
void play() {
std::cout << "动力装甲因太过脆弱而被损坏" << std::endl;
}
};
class FlyingPowder : public AbstractProduct {
public:
FlyingPowder() {
print();
play();
}
void print() {
std::cout << "得到一个飞路粉" << std::endl;
}
void play() {
std::cout << "飞路粉太香招来苍蝇" << std::endl;
}
};
class Goblins : public AbstractProduct {
public:
Goblins() {
print();
play();
}
void print() {
std::cout << "得到一个哥布林" << std::endl;
}
void play() {
std::cout << "暴躁的哥布林发起了进攻" << std::endl;
}
};
```
- 定义抽象工厂, 纯虚类
```cpp
class AbstractFactory {
public :
AbstractFactory() {}
virtual std::shared_ptr<AbstractProduct> getProduct() = 0;
};
```
- 定义三个具体方法工厂
```cpp
class MachineryFactory : public AbstractFactory{
public :
MachineryFactory() {}
std::shared_ptr<AbstractProduct> getProduct() {
return std::make_shared<PowerArmor>();
}
};
class MagicFactory : public AbstractFactory {
public:
MagicFactory() {}
std::shared_ptr<AbstractProduct> getProduct() {
return std::make_shared<FlyingPowder>();
}
};
class Greenfactory : public AbstractFactory {
public:
Greenfactory() {}
std::shared_ptr<AbstractProduct> getProduct() {
return std::make_shared<Goblins>();
}
};
```
- 用户使用方法
```cpp
#include "FactoryMethod.hpp"
int main() {
std::shared_ptr<AbstractFactory> factory = nullptr;
std::shared_ptr<AbstractProduct> product = nullptr;
factory = std::make_shared<MachineryFactory>();
product = factory->getProduct();
factory = std::make_shared<MagicFactory>();
product = factory->getProduct();
factory = std::make_shared<Greenfactory>();
product = factory->getProduct();
return 0;
}
```
- 效果
```cpp
./bin/design/FactoryMethod
得到一个动力装甲
动力装甲因太过脆弱而被损坏
得到一个飞路粉
飞路粉太香招来苍蝇
得到一个哥布林
暴躁的哥布林发起了进攻
```
## 总结
如果 想要新增一个产品只需要增加对应的产品和生产产品的工厂, 此方式不会修改或影响到之前已存在的产品代码. 由此可见, 相对于简单工厂更加符合 **开闭原则**, 工厂方法是使用频率最高的设计模式之一是很多开源框架和API类库的核心模式.
## 优点:
- 工厂方法用于创建客户所需产品,同时向客户隐藏某个具体产品类将被实例化的细节,用户只需关心所需产品对应的工厂;
- 工厂自主决定创建何种产品,并且创建过程封装在具体工厂对象内部,多态性设计是工厂方法模式的关键;
- 新加入产品时,无需修改原有代码,增强了系统的可扩展性,符合开闭原则。
## 缺点:
- 添加新产品时需要同时添加新的产品工厂,系统中类的数量成对增加,增加了系统的复杂度,更多的类需要编译和运行,增加了系统的额外开销;
- 工厂和产品都引入了抽象层客户端代码中均使用的抽象层AbstractFactory和AbstractSportProduct ),增加了系统的抽象层次和理解难度。
## 适用:
- 客户端不需要知道它所需要创建的对象的类;
- 抽象工厂类通过其子类来指定创建哪个对象(运用多态性设计和里氏代换原则)
**那什么时候该用工厂方法模式,而非简单工厂模式呢?**
之所以将某个代码块剥离出来,独立为函数或者类,原因是这个代码块的逻辑过于复杂,剥离之后能让代码更加清晰,更加可读、可维护。但是,如果代码块本身并不复杂,就几行代码而已,我们完全没必要将它拆分成单独的函数或者类。
基于这个设计思想当对象的创建逻辑比较复杂不只是简单的new一下就可以而是要组合其他类对象做各种初始化操作的时候我们推荐使用工厂方法模式将复杂的创建逻辑拆分到多个工厂类中让每个工厂类都不至于过于复杂。而使用简单工厂模式将所有的创建逻辑都放到一个工厂类中会导致这个工厂类变得很复杂。
除此之外在某些场景下如果对象不可复用那工厂类每次都要返回不同的对象。如果我们使用简单工厂模式来实现就只能选择第一种包含if分支逻辑的实现方式。如果我们还想避免烦人的if-else分支逻辑这个时候我们就推荐使用工厂方法模式。