简单工厂模式
简单工厂模式是一种创建型设计模式,通过一个工厂类来负责对象的实例。这种模式将对象创建的细节封装在工厂类中,客户端无需知道具体的创建过程,只需通过工厂类获取对象实例即可。
引入“简单工厂”设计模式的定义(实现意图):定义一个工厂类,该类的成员函数可以根据不同的参数创建并返回不同的类对象,被创建的对象所属的类一般都具有相同的父类。调用者无需关心创建对象的细节。
主要组成部分
- 工厂类(Factory):负责创建对象的类。它包含一个静态方法,根据传入的参数决定创建哪种具体产品。
- 产品接口(Product):定义了产品的基本行为和属性,所有具体产品类都需要实现这个接口。
- 具体产品类(ConcreteProduct):实现了产品接口的具体类,表示工厂可以创建的具体对象。
代码实现
以下代码,主要用简单工厂模式创建不同类型的怪物对象:
#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: //可能被子类访问的成员,用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 MonsterFactory
{
public:
Monster* createMonster(string strmontype)
{
Monster* prtnobj = nullptr;
if (strmontype == "udd") //udd代表要创建亡灵类怪物
{
prtnobj = new M_Undead(300, 50, 80);
}
else if (strmontype == "elm") //ele代表要创建元素类怪物
{
prtnobj = new M_Element(200, 80, 100);
}
else if (strmontype == "mec") //mec代表要创建机械类怪物
{
prtnobj = new M_Mechanic(400, 0, 110);
}
return prtnobj;
}
};
// 使用示例
int main()
{
MonsterFactory facobj;
Monster* undead = facobj.createMonster("udd"); //产生了一只亡灵类怪物,当然这里必须知道"udd"代表的是创建亡灵类怪物
Monster* element = facobj.createMonster("elm"); //产生了一只元素类怪物
Monster* mechanic = facobj.createMonster("mec"); //产生了一只机械类怪物
// 释放内存
delete undead;
delete element;
delete mechanic;
return 0;
}
简单工厂模式模式的 UML 图
简单工厂模式 UML 图解析
- 类关系:
- 类之间的父子关系通过实线箭头表示。子类(如
M_Undead
、M_Element
、M_Mechanic
)与父类Monster
之间有一条实线箭头,指向父类。 MonsterFactory
类与具体怪物类(如M_Undead
、M_Element
、M_Mechanic
)之间存在虚线箭头,表示依赖关系。虚线箭头指向被实例化的类,表明MonsterFactory
负责创建这些怪物对象。
- 类之间的父子关系通过实线箭头表示。子类(如
- 稳定与变化:
- 创建怪物的代码只需与
MonsterFactory
类交互,因此调用createMonster
成员函数的代码是稳定的。 - 但若要增加新类型的怪物,就需要修改
MonsterFactory
类中的createMonster
函数,这部分代码是变化的。
- 创建怪物的代码只需与
- 信息隐藏:
- 如果
MonsterFactory
由第三方开发,开发者不希望暴露具体怪物类(如M_Undead
、M_Element
、M_Mechanic
)的细节。通过提供createMonster
接口,开发者可以创建不同类型的怪物,从而实现具体实现的隐藏,并确保创建怪物的代码与具体类解耦,避免模块间的相互影响。
- 如果
优点和缺点
优点:
- 简化客户端代码:客户端只需通过工厂类获取对象,而无需了解对象的具体创建过程。
- 集中管理对象创建:所有对象的创建逻辑集中在工厂类中,便于维护和管理。
- 易于扩展:新增产品时,只需在工厂类中添加相应的创建逻辑,客户端代码无需修改。
缺点:
- 违反开闭原则:增加新产品需要修改工厂类的代码,导致工厂类可能变得臃肿。
- 赖于字符串参数:客户端需要了解产品类型的字符串标识,可能导致错误和不易维护。
- 不适合产品种类过多的情况:如果产品种类增多,工厂类会变得复杂且难以管理。
适用场景
- 产品具有相似结构:当需要创建的对象具有相似的结构或特性,且种类较少时。
- 客户端不关心创建过程:客户端希望通过简单的接口获取对象实例,而不关心其创建细节。
- 快速原型开发:在项目初期,快速实现功能时,可以使用简单工厂模式减少复杂性。
- 动态创建对象:需要根据不同条件动态创建对象的情况,适合使用简单工厂模式。