需求:假如现在游戏策划提出了三个需求:增加三个怪物,亡灵类怪物,元素类怪物,机械类怪物,他们都有生命值,魔法值和攻击力三个属性。
Monster作为怪物主类,M_Undead作为亡灵类,M_Element元素类,M_Mechanic机械类;
代码如下:
- 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 + 具体的类名来创建对象,这是一种具体类型的紧耦合关系。
简单工厂模式的实现思路:使用工厂类代替new来实现创建怪物的代码,用户在创建时候,与具体的类对象代码隔离,做到了松耦合。
- 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");
- 实例化一个工厂对象,然后通过向工厂中传递对应的标识来创建对象。
- /*
- 亡灵类动物
- 元素类动物
- 机械类动物
- */
- }
如果想新增加一个怪物,需要修改两个位置,首先,新增加一个新的怪物类,然后在工厂类的createMonster() 方法中再增加一个if else。这种做法不符合开闭原则。
开闭原则:代码的扩展性问题:对扩展开发,对修改关闭。当增加新功能,不应该通过修改已经存在的代码,比如在createMonster()中增加if else(), 而是应该通过扩展代码比如增加新类,增加新成员函数来进行扩展。假如上边要增加100个怪物类型,就要增加100个 if else(),这样的做法不可取,如果只增加几个,这样方法也可以,所以应该在代码的可读性和可扩展性之间做出权衡。
上面引入简单工厂模式的意图:定义一个工厂类,改类的成员函数可以根据不同的参数创建并返回不同的类对象,被创建的对象所属的类一般都具有相同的父类,比如上边的三个怪物类都继承自Monster类,调用者无需关系创建对象的细节。
简单工厂模式:实现了创建怪物代码语具体怪物类解耦合的效果,即创建一个类时,用户不必知道类名字,只需调用工厂类接口,将要创建的类的类型传入,即可创建类。
工厂和类之间是has a 关系。
工厂方法模式简称工厂模式或多态工厂模式;与简单工厂模式比,灵活性更强,实现也更加复杂,一如更多的新类。每一个工厂类对应了怪物类,比如亡灵类对应的工厂为亡灵工厂类。工厂模式:修改代码不如增加代码好,符合开闭原则。
简单工厂模式把创建对象这件事放在一个统一的工厂中处理,每增加一个类,就要在工厂中增加对应的if else语句;而工厂模式相当于创建一个框架,从而让子类来决定给对象如何创建。工厂方法模式往往需要创建一个与产品等级结构(层次)相同的工厂等级结构,这也新增加了新类的层次结构和数目。
- 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();
- // 工厂模式创建了一个工厂父类,在此基础上,又增加了每个怪物对应的工厂;
- // 与简单工厂模式比,比之前的复杂,但是灵活性更强,实现了 开闭原则,付出的代价是新增加了每个怪物的工厂类;
- //
- }
使用两个示例来说明和演示什么是抽象工厂模式,场景1是战斗场景模式,场景2是产品类
上边的三种怪物类别分别是:亡灵类,元素类和机械类。现在再将这三类怪物分为不同场景:沼泽地区,山脉地区,城镇地区。这样之前的三类怪物就成了9类怪物,类别如下图所示:
上图中有两个概念:产品等级结构 和 产品族。
抽象工厂模式按照产品族来生产商品。
一个工厂子类能够创建不止一种而是多种具有相同规则的怪物对象,也就是创建一个产品族的对象,那么就可以有效减少所创建的工厂子类数量,这就是抽象工厂模式的核心思想。
实现上面9种怪物:
- 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;
- }
1 如果增加一个新场景,比如增加一个森林场景,需要增加三个怪物,CMonsterForestUndead CMonsterForestElement CMonsterForestMechnical等类,然后再创建森林工厂来创建这三个怪物类,这样符合开闭原则。
2 如果增加新怪物,比如增加龙类,不仅要增加三个继承自CMonster的子类,还要修改Factory类,在该类中增加新的虚函数结构,比如createMonsterDragon(),同时各个子工厂中也要实现createMonsterDragon()类,这样的修改不符合开闭原则。
3 只增加一个产品族则符合开闭原则,只需要增加新工厂子类,这是该模式的优点。如果在某个场景中,比如在游戏中,怪物种类比较固定的情况下,更适合使用抽象工厂模式。
以生产芭比娃娃为例,芭比娃娃由三部分组成,分别是:身体,衣服,鞋子;有三个工厂都能生产芭比娃娃的这三个部分,中国工厂,日本工厂和美国工厂,产品结构图如下:
现在需求,制作两个芭比娃娃,第一个身体,衣服,鞋子全部采用中国厂商制造的部件。第二个芭比娃娃:中国生产的身体部件,日本工厂生产的衣服部件,美国产的鞋子部件。
类的设计思路:将身体,衣服,鞋子这三个部件实现为抽象类;实现一个抽象工厂,分别用来生产身体,衣服,鞋子这三个部件。实现这三个厂商的生产的部件。
- 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;
- }
抽象工厂模式定义: 提供一个抽象工厂接口,此接口负责定义一个产品族;
1 代码实现角度:修改工厂模式方法,使得一个工厂支持多个产品,就是抽象工厂模式;
2 从工厂数量来看:简单工厂模式需要的工厂类最少,工厂模式需要的工厂类较多,抽象工厂用来生产一个产品族的产品。
3 从实际项目角度:小项目用简单工厂模式,中大型项目:工厂模式;大型项目:抽象工厂模式。