工厂方法模式
工厂方法模式
工厂方法模式是一种创建型设计模式,它通过定义一个接口用于创建对象,但由子类决定实例化哪个类。与简单工厂模式不同,工厂方法模式将对象的创建委托给子类,从而实现更好的扩展性和灵活性。
引入"工厂方法模式(实现意图):定义一个用于创建对象的接口,但由子类决定要实例化的类是哪一个。该模式使得某个类的实例化延迟到子类。
主要组成部分
- 产品接口(Product):定义了工厂方法所创建的对象的接口。
- 具体产品(ConcreteProduct):实现了产品接口的具体类。
- 工厂接口(Creator):声明了工厂方法,返回一个产品对象。
- 具体工厂(ConcreteCreator):实现了工厂接口,返回具体产品的实例。
代码实现
以下代码,主要用工厂方法模式创建不同类型的怪物对象:
c++
#include <iostream>
#include <string>
using namespace std;
// 怪物父类
class Monster
{
public:
Monster(int life, int magic, int attack) : m_life(life), m_magic(magic), m_attack(attack) {}
virtual ~Monster() {} // 虚析构函数
protected:
int m_life; // 生命值
int m_magic; // 魔法值
int m_attack; // 攻击力
};
// 亡灵类怪物
class M_Undead : public Monster
{
public:
M_Undead(int life, int magic, int attack) : Monster(life, magic, attack)
{
cout << "一只亡灵类怪物来到了这个世界" << endl;
}
// 其他代码略....
};
// 元素类怪物
class M_Element : public Monster
{
public:
M_Element(int life, int magic, int attack) : Monster(life, magic, attack)
{
cout << "一只元素类怪物来到了这个世界" << endl;
}
// 其他代码略....
};
// 机械类怪物
class M_Mechanic : public Monster
{
public:
M_Mechanic(int life, int magic, int attack) : Monster(life, magic, attack)
{
cout << "一只机械类怪物来到了这个世界" << endl;
}
// 其他代码略....
};
// 工厂方法模式
// 所有工厂类的父类
class M_ParFactory
{
public:
virtual Monster* createMonster() = 0; // 纯虚函数
virtual ~M_ParFactory() {} // 虚析构函数
};
// 亡灵类怪物工厂
class M_UndeadFactory : public M_ParFactory
{
public:
virtual Monster* createMonster()
{
return new M_Undead(300, 50, 80); // 创建亡灵类怪物
}
};
// 元素类怪物工厂
class M_ElementFactory : public M_ParFactory
{
public:
virtual Monster* createMonster()
{
return new M_Element(200, 80, 100); // 创建元素类怪物
}
};
// 机械类怪物工厂
class M_MechanicFactory : public M_ParFactory
{
public:
virtual Monster* createMonster()
{
return new M_Mechanic(400, 0, 110); // 创建机械类怪物
}
};
// 全局创建怪物对象的函数
Monster* Gbl_CreateMonster(M_ParFactory* factory)
{
return factory->createMonster(); // 根据工厂创建怪物
}
// 创建怪物工厂子类模板
template <typename T>
class M_ChildFactory : public M_ParFactory
{
public:
virtual Monster* createMonster() {
return new T(300, 50, 80); // 创建具体类型的怪物
}
};
// 使用示例
int main()
{
// 使用具体工厂创建怪物
M_ParFactory* undeadFactory = new M_UndeadFactory();
Monster* undead = Gbl_CreateMonster(undeadFactory);
delete undead; // 释放内存
delete undeadFactory;
M_ParFactory* elementFactory = new M_ElementFactory();
Monster* element = Gbl_CreateMonster(elementFactory);
delete element; // 释放内存
delete elementFactory;
M_ParFactory* mechanicFactory = new M_MechanicFactory();
Monster* mechanic = Gbl_CreateMonster(mechanicFactory);
delete mechanic; // 释放内存
delete mechanicFactory;
// 使用模板工厂创建怪物
M_ChildFactory<M_Undead> undeadChildFactory;
Monster* undeadChild = Gbl_CreateMonster(&undeadChildFactory);
delete undeadChild; // 释放内存
return 0;
}
工厂方法模式模式的 UML 图
UML图解析
- 类关系:
- Monster 为抽象基类,定义了怪物的基本属性(
m_life
、m_magic
、m_attack
)。 - M_Undead 、M_Element 、M_Mechanic 类继承自 Monster,实现不同类型的怪物。
- Monster 为抽象基类,定义了怪物的基本属性(
- 工厂类:
- M_ParFactory 类为抽象工厂类,定义了创建怪物的接口
createMonster
。 - M_UndeadFactory 、M_ElementFactory 、M_MechanicFactory 类继承自 M_ParFactory,分别创建不同类型的怪物。
- M_ChildFactory 类为模板工厂,能够创建任意类型的怪物。
- M_ParFactory 类为抽象工厂类,定义了创建怪物的接口
类与方法
- 产品类 :
Monster
(抽象类)- 属性:
# m_life
:生命值,使用#
表示为保护属性,子类可以访问。# m_magic
:魔法值,使用#
表示为保护属性。# m_attack
:攻击力,使用#
表示为保护属性。
- 方法:
+ Monster(int life, int magic, int attack)
:构造函数,公开方法。- ~Monster()
:析构函数,私有方法。
- 属性:
M_Undead
、M_Element
、M_Mechanic
(具体类)- 方法:
+ M_Undead(int life, int magic, int attack)
:构造函数+ M_Element(int life, int magic, int attack)
:构造函数+ M_Mechanic(int life, int magic, int attack)
:构造函数
- 方法:
- 工厂类 :
M_ParFactory
(抽象工厂类)- 方法:
+ createMonster() : Monster*
:纯虚函数,返回一个怪物对象。- ~M_ParFactory()
:析构函数,私有方法。
- 方法:
M_UndeadFactory
、M_ElementFactory
、M_MechanicFactory
(具体工厂类)- 方法:
+ createMonster() : Monster*
:实现具体的怪物创建逻辑。
- 方法:
M_ChildFactory<T>
(模板工厂)- 方法:
+ createMonster() : Monster*
:创建具体类型的怪物。
- 方法:
优点和缺点
- 优点 :
- 通过工厂方法实现了对产品创建的封装,符合开闭原则,便于扩展。
- 客户端代码不需要知道具体的产品类,只需依赖于产品接口。
- 缺点 :
- 增加新产品时,需要创建新的具体工厂类,可能导致类的数量增加。
- 由于每种产品都需要一个具体工厂,可能会引入额外的复杂性。
适用场景
- 当一个类不知道它所需要的对象的具体类型时。
- 当一个类希望由子类来指定所创建的对象时。
- 当需要在运行时决定创建哪个产品时。
优点和缺点
- 优点 :
- 通过工厂方法实现了对产品创建的封装,符合开闭原则,便于扩展。
- 客户端代码不需要知道具体的产品类,只需依赖于产品接口。
- 缺点 :
- 增加新产品时,需要创建新的具体工厂类,可能导致类的数量增加。
- 由于每种产品都需要一个具体工厂,可能会引入额外的复杂性。
适用场景
- 当一个类不知道它所需要的对象的具体类型时。
- 当一个类希望由子类来指定所创建的对象时。
- 当需要在运行时决定创建哪个产品时。