工厂方法模式(Factory Method) - 指南
在本章节中,我们将开始讨论五种创建型设计模式中的工厂方法模式(Factory Method)。
理论部分
定义
工厂方法模式是一种创建型设计模式,它提供了一种将对象实例化过程封装起来的方法,让子类决定要实例化的类是哪一个。工厂方法让类的实例化推迟到子类中进行。
概括来说就是:在父类中提供一个创建对象的接口来让子类决定具体实例化什么类型的对象。
在游戏中,我们需要设计多种武器种类,每个武器和道具都有不同的属性功能以及品质等等私有字段,这种情况下,我们便可以借助武器装备道具工厂对象根据游戏状态或者玩家操作动态地创建具体的装备对象。
- 例如:我们定义了一个武器基类
Weapon
,其中有一个纯虚方法use
代表使用这把武器的逻辑。
//武器基类
class Weapon
{
public:
virtual void use() = 0;
};
那么我们便可以派生出剑和弓的子类,它们分别有自己的使用逻辑。
// 武器 - 剑
class Sword
: public Weapon
{
public:
void use() override
{
std::cout <<
"挥舞剑!" << std::endl;
}
};
// 武器 - 弓
class Bow
: public Weapon
{
public:
void use() override
{
std::cout <<
"射出箭!" << std::endl;
}
};
通常来说,如果我们不考虑使用任何设计模式,这两个子类就是可以直接被实例化和使用的。
如果我们要使用工厂方法模式进行优化,就需要创建工厂基类,
// 武器的工厂模式基类
class WeaponFactory
{
public:
virtual Weapon* createWeapon() = 0;
// 纯虚函数
};
工厂类约定所有生成具体武器的工厂都需要实现createWeapon
方法,对外返回创建后的对象。
所以我们就需要实现具体的工厂子类了,对应了我们生成武器剑的工厂和生成武器弓的工厂。
// 武器剑的工厂
class SwordFactory
: public WeaponFactory
{
public:
Weapon* createWeapon() override
{
return new Sword();
}
};
// 武器弓的工厂
class BowFactory
: public WeaponFactory
{
public:
Weapon* createWeapon() override
{
return new Bow();
}
};
这样,我们便可以通过具体的工厂对象创建对应的武器产品了。
- 由此我们可以得出工厂模式的几个关键要素:
- 抽象产品(Product):定义了产品的接口
如Weapon
基类(重要声明,意味着后续所有创建者及其子类构建的对象都将是通用的)
- 具体产品(ConcreteProduct):实现抽象产品接口的具体类
如Sword
和Bow
子类(抽象产品接口的不同实现)
- 抽象创建者(Creator):声明工厂方法,返回产品对象
如WeaponFactory
基类(不直接进行具体的产品创建,而是负责对创建的接口进行声明,后续所有的创建者返回的对象类型都必须与产品类型相匹配)
- 具体创建者(ConcreteCreator):重写工厂方法,返回具体产品实例
如SwordFactory
和BowFactory
子类(重写抽象工厂的方法,实例化不同的产品对象进行返回)
所以我们可以得出工厂方法的显著优点:
- 解耦将客户端代码与具体类依赖
将具体的产品代码与使用该产品的客户端内容进行分离
- 符合开闭原则,提高系统的可扩展性
引入新产品无需修改现有代码
- 符合单一职责原则,封装复杂的对象创建逻辑
工厂内部屏蔽对象创建和初始化的复杂操作
- 提高可维护性
将对象创建代码的逻辑集中到一处方便后续修改维护
- 支持更多的产品组合
抽象工厂模式的基础思想
应用场景
- 日志系统
提供输出到控制台、文件、网络和数据库的多种方法
- 数据库驱动
提供连接到MySql、SQLite、PostgreSQL等不同数据库的驱动层
- 文档生成
将同一份内容生成HTML、PDF、Markdown等不同格式的文档。
缺点
引入许多新的子类,可能增加代码复杂度
单独的工厂方法模式无法应对复杂的产品族和变种
这篇博文是我的学习笔记