目录
[1.1 简单工厂模式引入](#1.1 简单工厂模式引入)
[1.2 简单工厂模式](#1.2 简单工厂模式)
[1.3 简单工厂模式利弊分析](#1.3 简单工厂模式利弊分析)
[1.4 简单工厂模式的UML图](#1.4 简单工厂模式的UML图)
[2.1 工厂模式和简单工厂模式比较](#2.1 工厂模式和简单工厂模式比较)
[2.2 工厂模式代码实现](#2.2 工厂模式代码实现)
[2.3 工厂模式UML](#2.3 工厂模式UML)
[3.1 战斗场景分类范例1](#3.1 战斗场景分类范例1)
[3.1.1 抽象工程代码实现](#3.1.1 抽象工程代码实现)
[3.1.2 抽象工厂模式优缺点](#3.1.2 抽象工厂模式优缺点)
[3.1.3 抽象工厂模式UML](#3.1.3 抽象工厂模式UML)
[3.2 抽象工厂范例2](#3.2 抽象工厂范例2)
[3.2.1 代码实现](#3.2.1 代码实现)
[3.2.2 UML](#3.2.2 UML)
一、简单工厂模式
1.1 简单工厂模式引入
**需求:**假如现在游戏策划提出了三个需求:增加三个怪物,亡灵类怪物,元素类怪物,机械类怪物,他们都有生命值,魔法值和攻击力三个属性。
Monster作为怪物主类,M_Undead作为亡灵类,M_Element元素类,M_Mechanic机械类;
代码如下:
cpp
namespace _namespace2
{
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;
}
};
}
void test1()
{
_namespace2::Monster *m1 = new _namespace2::M_Undead(300, 100, 100);
_namespace2::Monster *m2 = new _namespace2::M_Element(300, 100, 100);
_namespace2::Monster *m3 = new _namespace2::M_Mechanic(300, 100, 100);
/*
亡灵类动物
元素类动物
机械类动物
*/
}
上边使用new + 具体的类名来创建对象,这是一种具体类型的紧耦合关系。
1.2 简单工厂模式
简单工厂模式的实现思路:使用工厂类代替new来实现创建怪物的代码,用户在创建时候,与具体的类对象代码隔离,做到了松耦合。
cpp
namespace _namespace1
{
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 MonsterFactor
{
public:
Monster * createMonster(string strmontype)
{
Monster *ptrobj = nullptr;
if (strmontype == "a")
{
ptrobj = new M_Undead(300, 100, 100);
}
else if (strmontype == "b")
{
ptrobj = new M_Element(300, 100, 100);
}
else if (strmontype == "c")
{
ptrobj = new M_Mechanic(300, 100, 100);
}
return ptrobj;
}
};
}
void test2()
{
//2 简单工厂模式的实现思路:使用工厂类可以实现创建怪物的代码,用户在创建时候,与具体的类对象要实现的逻辑代码隔离。
_namespace1::MonsterFactor fac;
_namespace1::Monster *m1 = fac.createMonster("a");
_namespace1::Monster *m2 = fac.createMonster("b");
_namespace1::Monster *m3 = fac.createMonster("c");
实例化一个工厂对象,然后通过向工厂中传递对应的标识来创建对象。
/*
亡灵类动物
元素类动物
机械类动物
*/
}
1.3 简单工厂模式利弊分析
如果想新增加一个怪物,需要修改两个位置,首先,新增加一个新的怪物类,然后在工厂类的createMonster **()**方法中再增加一个if else。这种做法不符合开闭原则。
**开闭原则:**代码的扩展性问题:对扩展开发,对修改关闭。当增加新功能,不应该通过修改已经存在的代码,比如在createMonster()中增加if else(), 而是应该通过扩展代码比如增加新类,增加新成员函数来进行扩展。假如上边要增加100个怪物类型,就要增加100个 if else(),这样的做法不可取,如果只增加几个,这样方法也可以,所以应该在代码的可读性和可扩展性之间做出权衡。
**上面引入简单工厂模式的意图:**定义一个工厂类,改类的成员函数可以根据不同的参数创建并返回不同的类对象,被创建的对象所属的类一般都具有相同的父类,比如上边的三个怪物类都继承自Monster类,调用者无需关系创建对象的细节。
**简单工厂模式:**实现了创建怪物代码语具体怪物类解耦合的效果,即创建一个类时,用户不必知道类名字,只需调用工厂类接口,将要创建的类的类型传入,即可创建类。
1.4 简单工厂模式的UML图
工厂和类之间是has a 关系。
二、工厂方法模式
工厂方法模式简称工厂模式或多态工厂模式;与简单工厂模式比,灵活性更强,实现也更加复杂,一如更多的新类。每一个工厂类对应了怪物类,比如亡灵类对应的工厂为亡灵工厂类。工厂模式:修改代码不如增加代码好,符合开闭原则。
2.1 工厂模式和简单工厂模式比较
简单工厂模式把创建对象这件事放在一个统一的工厂中处理,每增加一个类,就要在工厂中增加对应的if else语句;而工厂模式相当于创建一个框架,从而让子类来决定给对象如何创建。工厂方法模式往往需要创建一个与产品等级结构(层次)相同的工厂等级结构,这也新增加了新类的层次结构和数目。
2.2 工厂模式代码实现
cpp
namespace _sp1
{
// 怪物类父类
class CMonster
{
public:
CMonster(int life,int maigc,int attack):m_life(life),m_magic(maigc), m_attack(attack)
{
}
protected:
int m_life;
int m_magic;
int m_attack;
};
// 亡灵类
class CUnded : public CMonster
{
public:
CUnded(int life, int maigc, int attack) :CMonster(life, maigc, attack)
{
cout << "亡灵类来到世界" << endl;
}
private:
};
// 元素类
class CEle : public CMonster
{
public:
CEle(int life, int maigc, int attack) :CMonster(life, maigc, attack)
{
cout << "元素类来到世界" << endl;
}
private:
};
// 机械类
class CMecanical : public CMonster
{
public:
CMecanical(int life, int maigc, int attack) :CMonster(life, maigc, attack)
{
cout << "机械类来到世界" << endl;
}
};
// 简单工厂模式:创建一个工厂类,在工厂类中返回对应的 怪物类;
// 工厂方法
// 1 创建一个工厂基类;
class CFactorMonster
{
public:
virtual CMonster * createMonster() = 0;
virtual ~CFactorMonster()
{
}
};
// 2 创建每个怪物的工厂
class CFactorUnded : public CFactorMonster
{
public:
virtual CMonster * createMonster()
{
CMonster *ptmp = new CUnded(200,300,400);
return ptmp;
}
};
class CFactorCEle : public CFactorMonster
{
public:
virtual CMonster * createMonster()
{
CMonster *ptmp = new CEle(200, 300, 400); // 多态
return ptmp;
}
};
// 创建一个全局方法
CMonster *GlobalCreateMonster(CFactorMonster *factory)
{
return factory->createMonster(); // 多态
}
}
void test2()
{
// 先 创建一个工厂父类;由于每个工厂具有固定的步骤,所以有工厂父类;
_sp1::CFactorMonster *p = new _sp1::CFactorUnded();
_sp1::CMonster *pp = p->createMonster();
_sp1::CFactorMonster *p2 = new _sp1::CFactorCEle();
_sp1::CMonster *pp2 = p2->createMonster();
// 工厂模式创建了一个工厂父类,在此基础上,又增加了每个怪物对应的工厂;
// 与简单工厂模式比,比之前的复杂,但是灵活性更强,实现了 开闭原则,付出的代价是新增加了每个怪物的工厂类;
//
}
2.3 工厂模式UML
三、抽象工厂模式
使用两个示例来说明和演示什么是抽象工厂模式,场景1是战斗场景模式,场景2是产品类
3.1 战斗场景分类范例1
上边的三种怪物类别分别是:亡灵类,元素类和机械类。现在再将这三类怪物分为不同场景:沼泽地区,山脉地区,城镇地区。这样之前的三类怪物就成了9类怪物,类别如下图所示:
上图中有两个概念:产品等级结构 和 产品族。
抽象工厂模式按照产品族来生产商品。
一个工厂子类能够创建不止一种而是多种具有相同规则的怪物对象,也就是创建一个产品族的对象,那么就可以有效减少所创建的工厂子类数量,这就是抽象工厂模式的核心思想。
3.1.1 抽象工程代码实现
实现上面9种怪物:
cpp
namespace _nsp1
{
// 怪物类父类
class CMonster
{
public:
CMonster(int life, int maigc, int attack) :m_life(life), m_magic(maigc), m_attack(attack)
{
}
protected:
int m_life;
int m_magic;
int m_attack;
};
/// 下面分别实现这9个类别,每个怪物类都继承自怪物父类
// 城镇亡灵类
class CMonsterTownUndead : public CMonster
{
public:
CMonsterTownUndead(int life, int magic, int attack) : CMonster(life, magic, attack)
{
cout << "一个城镇亡灵类型怪物来到了这个世界" << endl;
}
};
// 城镇元素类
class CMonsterTownElement : public CMonster
{
public:
CMonsterTownElement(int life, int magic, int attack) : CMonster(life, magic, attack)
{
cout << "一个城镇元素类型怪物来到了这个世界" << endl;
}
};
// 城镇机械类
class CMonsterTownMechanic : public CMonster
{
public:
CMonsterTownMechanic(int life, int magic, int attack) : CMonster(life, magic, attack)
{
cout << "一个城镇机械类型怪物来到了这个世界" << endl;
}
};
/// 山脉类
// 山脉亡灵类
class CMonsterMaintainUndead : public CMonster
{
public:
CMonsterMaintainUndead(int life, int magic, int attack) : CMonster(life, magic, attack)
{
cout << "一个山脉亡灵类型怪物来到了这个世界" << endl;
}
};
// 山脉元素类
class CMonsterMaintainElement : public CMonster
{
public:
CMonsterMaintainElement(int life, int magic, int attack) : CMonster(life, magic, attack)
{
cout << "一个山脉元素类型怪物来到了这个世界" << endl;
}
};
// 山脉机械类
class CMonsterMaintainMechanic : public CMonster
{
public:
CMonsterMaintainMechanic(int life, int magic, int attack) : CMonster(life, magic, attack)
{
cout << "一个山脉机械类型怪物来到了这个世界" << endl;
}
};
/// 沼泽类
// 沼泽亡灵类
class CMonsterMarshUndead : public CMonster
{
public:
CMonsterMarshUndead(int life, int magic, int attack) : CMonster(life, magic, attack)
{
cout << "一个沼泽亡灵类型怪物来到了这个世界" << endl;
}
};
// 沼泽元素类
class CMonsterMarshElement : public CMonster
{
public:
CMonsterMarshElement(int life, int magic, int attack) : CMonster(life, magic, attack)
{
cout << "一个沼泽元素类型怪物来到了这个世界" << endl;
}
};
// 沼泽机械类
class CMonsterMarshMechanic : public CMonster
{
public:
CMonsterMarshMechanic(int life, int magic, int attack) : CMonster(life, magic, attack)
{
cout << "一个沼泽机械类型怪物来到了这个世界" << endl;
}
};
/// 创建工厂
class CMonsterFactory
{
public:
virtual CMonster *createMonsterUndead() = 0;
virtual CMonster *createMonsterElement() = 0;
virtual CMonster *createMonsterMechanic() = 0;
virtual ~CMonsterFactory()
{
}
};
// 城镇类工厂:一个工厂能生产一个产品族
class CMonsterFactoryTown : public CMonsterFactory
{
virtual CMonster *createMonsterUndead()
{
return new CMonsterTownUndead(100, 100, 100);
}
virtual CMonster *createMonsterElement()
{
return new CMonsterTownElement(100, 100, 100);
}
virtual CMonster *createMonsterMechanic()
{
return new CMonsterTownMechanic(100, 100, 100);
}
};
// 山脉类怪物工厂
class CMonsterFactoryMaintain : public CMonsterFactory
{
virtual CMonster *createMonsterUndead()
{
return new CMonsterMaintainUndead(100, 100, 100);
}
virtual CMonster *createMonsterElement()
{
return new CMonsterMaintainElement(100, 100, 100);
}
virtual CMonster *createMonsterMechanic()
{
return new CMonsterMaintainMechanic(100, 100, 100);
}
};
// 沼泽类怪物工厂
class CMonsterFactoryMarsh : public CMonsterFactory
{
virtual CMonster *createMonsterUndead()
{
return new CMonsterMarshUndead(100, 100, 100);
}
virtual CMonster *createMonsterElement()
{
return new CMonsterMarshElement(100, 100, 100);
}
virtual CMonster *createMarshMechanic()
{
return new CMonsterMaintainMechanic(100, 100, 100);
}
};
}
int main()
{
_nsp1::CMonsterFactory *pc = new _nsp1::CMonsterFactoryTown();
_nsp1::CMonster *pM1 = pc->createMonsterUndead();
_nsp1::CMonster *pM2 = pc->createMonsterMechanic();
_nsp1::CMonster *pM3 = pc->createMonsterElement();
/*
一个城镇亡灵类型怪物来到了这个世界
一个城镇机械类型怪物来到了这个世界
一个城镇元素类型怪物来到了这个世界
*/
system("pause");
return 0;
}
3.1.2 抽象工厂模式优缺点
1 如果增加一个新场景,比如增加一个森林场景,需要增加三个怪物,CMonsterForestUndead CMonsterForestElement CMonsterForestMechnical等类,然后再创建森林工厂来创建这三个怪物类,这样符合开闭原则。
2 如果增加新怪物,比如增加龙类,不仅要增加三个继承自CMonster的子类,还要修改Factory类,在该类中增加新的虚函数结构,比如createMonsterDragon(),同时各个子工厂中也要实现createMonsterDragon()类,这样的修改不符合开闭原则。
3 只增加一个产品族则符合开闭原则,只需要增加新工厂子类,这是该模式的优点。如果在某个场景中,比如在游戏中,怪物种类比较固定的情况下,更适合使用抽象工厂模式。
3.1.3 抽象工厂模式UML
3.2 抽象工厂范例2
以生产芭比娃娃为例,芭比娃娃由三部分组成,分别是:身体,衣服,鞋子;有三个工厂都能生产芭比娃娃的这三个部分,中国工厂,日本工厂和美国工厂,产品结构图如下:
现在需求,制作两个芭比娃娃,第一个身体,衣服,鞋子全部采用中国厂商制造的部件。第二个芭比娃娃:中国生产的身体部件,日本工厂生产的衣服部件,美国产的鞋子部件。
3.2.1 代码实现
类的设计思路:将身体,衣服,鞋子这三个部件实现为抽象类;实现一个抽象工厂,分别用来生产身体,衣服,鞋子这三个部件。实现这三个厂商的生产的部件。
cpp
namespace _namesp1
{
// 1 三个组成部件
// 身体部件 和 生产工厂
class CBody
{
public:
virtual void productName() = 0;
virtual ~CBody() {}
};
class CBody_China : public CBody
{
public :
virtual void productName()
{
cout << "中国牌身体" << endl;
}
};
class CBody_America : public CBody
{
public:
virtual void productName()
{
cout << "美国牌身体" << endl;
}
};
class CBody_Japan : public CBody
{
public:
virtual void productName()
{
cout << "日本牌身体" << endl;
}
};
// 衣服部件 和 生产工厂
class CCloth
{
public:
virtual void productName() = 0;
virtual ~CCloth() {}
};
class CCloth_China : public CCloth
{
public:
virtual void productName()
{
cout << "中国牌衣服" << endl;
}
};
class CCloth_America : public CCloth
{
public:
virtual void productName()
{
cout << "美国牌衣服" << endl;
}
};
class CCloth_Japan : public CCloth
{
public:
virtual void productName()
{
cout << "日本牌衣服" << endl;
}
};
// 鞋子部件 和 生产工厂
class CShoes
{
public:
virtual void productName() = 0;
virtual ~CShoes() {}
};
class CShoes_China : public CShoes
{
public:
virtual void productName()
{
cout << "中国牌鞋子" << endl;
}
};
class CShoes_America : public CShoes
{
public:
virtual void productName()
{
cout << "美国牌鞋子" << endl;
}
};
class CShoes_Japan : public CShoes
{
public:
virtual void productName()
{
cout << "日本牌鞋子" << endl;
}
};
// 组装芭比娃娃类
class CBarbieDoll
{
public:
CBarbieDoll(CBody *body1, CCloth *cloth1, CShoes *shoes1):body(body1),cloth(cloth1),shoes(shoes1) {}
// 组成芭比娃娃
void composeBar()
{
cout << "组成一个芭比娃娃" << endl;
body->productName();
cloth->productName();
shoes->productName();
}
private:
CBody *body;
CCloth *cloth;
CShoes *shoes;
};
// 抽象工厂类
class CAbstractFactory
{
public:
virtual CBody* createBody() = 0;
virtual CCloth* createCloth() = 0;
virtual CShoes* createShoes() = 0;
virtual ~CAbstractFactory()
{
}
};
// 中国工厂
class ChinaFactory : public CAbstractFactory
{
public:
virtual CBody * createBody()
{
return new CBody_China;
}
virtual CCloth * createCloth()
{
return new CCloth_China;
}
virtual CShoes * createShoes()
{
return new CShoes_China;
}
};
// 日本工厂
class JapanFactory : public CAbstractFactory
{
public:
virtual CBody * createBody()
{
return new CBody_Japan;
}
virtual CCloth * createCloth()
{
return new CCloth_Japan;
}
virtual CShoes * createShoes()
{
return new CShoes_Japan;
}
};
// 美国工厂
class AmericaFactory : public CAbstractFactory
{
public:
virtual CBody * createBody()
{
return new CBody_America;
}
virtual CCloth * createCloth()
{
return new CCloth_America;
}
virtual CShoes * createShoes()
{
return new CShoes_America;
}
};
}
int main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到"输出"窗口
// 生产第一个娃娃
_namesp1::CAbstractFactory *pChinaFactory = new _namesp1::ChinaFactory();
_namesp1::CBody *pChinaBody = pChinaFactory->createBody();
_namesp1::CCloth *pChinaCloth = pChinaFactory->createCloth();
_namesp1::CShoes *pChinaShoes = pChinaFactory->createShoes();
// 组装
_namesp1::CBarbieDoll *pbar = new _namesp1::CBarbieDoll(pChinaBody, pChinaCloth, pChinaShoes);
pbar->composeBar();
// 生产第二个娃娃
_namesp1::CAbstractFactory *pAmericaFactory = new _namesp1::AmericaFactory();
_namesp1::CAbstractFactory *pJapanFactory = new _namesp1::JapanFactory();
_namesp1::CBody *pChinaBody2 = pChinaFactory->createBody();
_namesp1::CCloth *pChinaCloth2 = pJapanFactory->createCloth();
_namesp1::CShoes *pChinaShoes2 = pAmericaFactory->createShoes();
// 组装
_namesp1::CBarbieDoll *pbar2 = new _namesp1::CBarbieDoll(pChinaBody2, pChinaCloth2, pChinaShoes2);
pbar2->composeBar();
/*
组成一个芭比娃娃
中国牌身体
中国牌衣服
中国牌鞋子
组成一个芭比娃娃
中国牌身体
日本牌衣服
美国牌鞋子
*/
system("pause");
return 0;
}
抽象工厂模式定义: 提供一个抽象工厂接口,此接口负责定义一个产品族;
3.2.2 UML
四、三个工厂模式总结
1 代码实现角度:修改工厂模式方法,使得一个工厂支持多个产品,就是抽象工厂模式;
2 从工厂数量来看:简单工厂模式需要的工厂类最少,工厂模式需要的工厂类较多,抽象工厂用来生产一个产品族的产品。
3 从实际项目角度:小项目用简单工厂模式,中大型项目:工厂模式;大型项目:抽象工厂模式。