工厂模式:通过把创建对象的代码包装起来,做到创建对象的代码与具体的业务逻辑代码相隔离的目的。
工厂模式可以细分为:简单工厂模式,工厂方法模式,抽象工厂模式。
1.代码示例
#include <iostream>
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;
}
// 其他代码略
};
int main()
{
Monster* pM1 = new M_Undead(300, 50, 80); // 产生一只亡灵类怪物
Monster* pM2 = new M_Element(200, 80, 100); // 产生一只元素类怪物
Monster* pM3 = new M_Mechanic(400, 0, 110); // 产生一只机械类怪物
// 释放资源
delete pM1;
delete pM2;
delete pM3;
return 0;
}
在上面的代码中,使用 new 具体类名
来创建对象是一种依赖具体类型的紧耦合关系。
简单工厂模式的实现思路:使用工厂类可以实现创建怪物的代码与各个具体怪物类对象要实现的逻辑代码隔离。把依赖范围尽可能缩小,把容易变化的代码段限制在一个小范围内,就可以在很大程度上提高代码的可维护性和可扩展性。
#include <iostream>
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") // elm代表要创建元素类怪物
{
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* pM1 = facobj.createMonster("udd"); // 创建一只亡灵类怪物,当然,这里必须知道udd代表的是创建亡灵类怪物
Monster* pM2 = facobj.createMonster("elm"); // 创建一只元素类怪物
Monster* pM3 = facobj.createMonster("mec"); // 创建一只机械类怪物
// 释放资源
delete pM1;
delete pM2;
delete pM3;
return 0;
}
如果用 static 修饰成员函数 createMonster,此时简单工厂模式又可以称为静态工厂方法模式(Static Factory Method)。
#include <iostream>
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:
// 静态工厂方法模式(Static Factory Method)
static Monster* createMonster(string strmontype)
{
Monster* prtnobj = nullptr;
if (strmontype == "udd") // udd代表要创建亡灵类怪物
{
prtnobj = new M_Undead(300, 50, 80);
}
else if (strmontype == "elm") // elm代表要创建元素类怪物
{
prtnobj = new M_Element(200, 80, 100);
}
else if (strmontype == "mec") // mec代表要创建机械类怪物
{
prtnobj = new M_Mechanic(400, 0, 110);
}
return prtnobj;
}
};
int main()
{
Monster* pM1 = MonsterFactory::createMonster("udd"); // 创建一只亡灵类怪物,当然,这里必须知道udd代表的是创建亡灵类怪物
Monster* pM2 = MonsterFactory::createMonster("elm"); // 创建一只元素类怪物
Monster* pM3 = MonsterFactory::createMonster("mec"); // 创建一只机械类怪物
// 释放资源
delete pM1;
delete pM2;
delete pM3;
return 0;
}
如果想要增加新怪物,可以通过增加新的 if-else 分支来实现,但这违背了面向对象程序设计原则中的开闭原则(Open Close Principle, OCP)。
开闭原则,说的是代码扩展性问题,即对扩展开放,对修改关闭(封闭)。
开闭原则的详细解释:当增加新功能,不应该通过修改已经存在的代码来进行,而是应该通过扩展代码(比如增加新类、增加新成员函数)来进行。
如果 if-else 分支不多,则适当违反开闭原则是完全可以接受的。大家要在代码的可读性和可扩展性之间做出权衡。
UML 如下:
2.简单工厂模式的定义(实现意图)
定义一个工厂类(MonsterFactory),该类的成员函数(createMonster)可以根据不同参数创建并返回不同的类对象,被创建的对象所属的类(M_Undead、M_Element、M_Mechanic)一般都具有相同的父类(Monster)。调用者(这里指main函数)无需关心创建对象的细节。
简单工厂方法模式实现了创建怪物类代码(createMonster)与具体怪物类(M_Undead、M_Element、M_Mechanic)解耦合的效果。