new 创建的是堆对象,可以实现多态。
工厂模式:通过把创建对象的代码包装起来,做到创建对象的代码与具体的业务逻辑代码相隔离的目的。
工厂模式细分:
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
一、简单工厂模式 Simple Factory
1.1 功能策划
- 怪物分类:亡灵类怪物、元素类怪物、机械类怪物
- 共有属性:生命值、魔法值、攻击力
- Monster作为父类,Undead(亡灵类)、Element(元素类)、Mechanic(机械类)
1.2 示例代码一(未引入工厂类)
```cppinclude
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 Undead : public Monster { public: Undead(int life, int magic, int attack) : Monster(life, magic, attack) { cout << “A undead monster came into the world.” << endl; } // 其他逻辑代码
~Undead() { }
};
// 元素类怪物 class Element : public Monster { public: Element(int life, int magic, int attack) : Monster(life, magic, attack) { cout << “A element monster came into the world.” << endl; } // 其他逻辑代码
~Element() { }
}; // 机械类怪物 class Mechanic : public Monster { public: Mechanic(int life, int magic, int attack) : Monster(life, magic, attack) { cout << “A mechanic monster came into the world.” << endl; } // 其他逻辑代码
~Mechanic() { }
};
int main(int argc, char argv[]) { Monster pM1 = new Undead(300, 50, 80); Monster pM2 = new Element(200, 50, 100); Monster pM3 = new Mechanic(400, 0, 110);
delete pM1;delete pM2;delete pM3;
}
当游戏内容增加更多的怪物,需要创建更多对象,改变可能较大不方便维护。即:- 使用new + 具体类名来创建一种依赖具体类型的紧耦合关系- 使用工厂类 **实现创建怪物的代码** 与 **各个具体怪物类对象要实现的逻辑 **代码隔离- 封装变化:把依赖范围尽可能缩小,把容易变化的代码段限制在一个小范围内,就可以在很大程度上提高代码的可维护性和可扩展性- **通过增加新的 if...else..分支来达到支持新怪物增加的目的 -- 违背了面向对象程序设计的原则 -- 开闭原则**开闭原则- 说的是代码扩展性问题 -- 对扩展开放,对修改关闭(封闭)- **当增加新功能,不应该通过修改已经存在的代码来进行,而是应该通过扩展代码(比如增加新类,增加新成员函数)来进行****如果 if..else..分支不多(没有数十上百个),则适当违法开闭原则是可以接受的。需要在可读性和可扩展性之间做出权衡**<a name="LgsqM"></a>## 1.3 引入简单工厂模式引入简单工厂模式的定义(实现意图:定义一个工厂类(MonsterFactory),该类的成员函数(`createMonster()`)可以根据不同参数创建并返回不同的类对象,被创建的对象所属的类(Undead,Element,Mechanic)一般都具有相同的父类(Monster),调用者无需关心创建对象的细节。简单工厂方法模式:实现了创建怪物类代码(`createMonster()`),与具体怪物类(Undead,Element,Mechanic)解耦合<a name="xnygb"></a>## 1.4 示例代码二(创建工厂类后)```cpp#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:int m_life; // 生命值int m_magic; // 魔法值int m_attack; // 攻击力};// 亡灵类怪物class Undead : public Monster {public:Undead(int life, int magic, int attack): Monster(life, magic, attack){cout << "A undead monster came into the world." << endl;}// 其他代码略...~Undead() { }};// 元素类怪物class Element : public Monster {public:Element(int life, int magic, int attack): Monster(life, magic, attack){cout << "A element monster came into the world." << endl;}// 其他代码略...~Element() { }};// 机械类怪物class Mechanic : public Monster {public:Mechanic(int life, int magic, int attack): Monster(life, magic, attack){cout << "A mechanic monster came into the world." << endl;}// 其他代码略...~Mechanic() { }};// 怪物工厂类-1class MonsterFactory {public:Monster* createMonster(string monsterType){Monster* monster = nullptr;if (monsterType == "undead") { // 亡灵类monster = new Undead(300, 50, 60);}else if (monsterType == "element") { // 元素类monster = new Element(200, 80, 100);}else if (monsterType == "mechanic") { // 机械类monster = new Mechanic(400, 0, 110);}return monster;}};// 静态怪物工厂类class StaticMonsterFactory {public:static Monster* createMonster(string monsterType){Monster* monster = nullptr;if (monsterType == "undead") { // 亡灵类monster = new Undead(300, 50, 60);}else if (monsterType == "element") { // 元素类monster = new Element(200, 80, 100);}else if (monsterType == "mechanic") { // 机械类monster = new Mechanic(400, 0, 110);}return monster;}};void simpleFactorMode(){{MonsterFactory monsterFactory; // 需要知道每个怪物对应的枚举值或者字符串// 产生一只亡灵类怪物Monster* p_undead = monsterFactory.createMonster("undead");// 产生一只元素类怪物Monster* p_element = monsterFactory.createMonster("element");// 产生一只机械类怪物Monster* p_mechanic = monsterFactory.createMonster("mechanic");// 释放资源delete p_undead;delete p_element;delete p_mechanic;}cout << endl;{ // 静态怪物工厂类// 产生一只亡灵类怪物Monster* p_undead = StaticMonsterFactory::createMonster("undead");// 产生一只元素类怪物Monster* p_element = StaticMonsterFactory::createMonster("element");// 产生一只机械类怪物Monster* p_mechanic = StaticMonsterFactory::createMonster("mechanic");// 释放资源delete p_undead;delete p_element;delete p_mechanic;}}
1.5 类图
二、工厂方法模式 Factory Method
2.1 引入工厂方法模式
与简单工厂模式比,灵活性更强,实现也更加复杂,引入更多的新类。
UndeadFactory、ElementFactory、MechanicFactory类,有一个共同的父类MasterFactory(工厂抽象类)。
符合开闭原则,付出的代价是需要新增加多个新的工厂类。
2.2 示例代码
#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:int m_life; // 生命值int m_magic; // 魔法值int m_attack; // 攻击力};// 亡灵类怪物class Undead : public Monster {public:Undead(int life, int magic, int attack): Monster(life, magic, attack){cout << "A undead monster came into the world." << endl;}// 其他代码略...~Undead() { }};// 元素类怪物class Element : public Monster {public:Element(int life, int magic, int attack): Monster(life, magic, attack){cout << "A element monster came into the world." << endl;}// 其他代码略...~Element() { }};// 机械类怪物class Mechanic : public Monster {public:Mechanic(int life, int magic, int attack): Monster(life, magic, attack){cout << "A mechanic monster came into the world." << endl;}// 其他代码略...~Mechanic() { }};// 怪物工厂父类class MonsterFactory {public:// 具体的实现在子类中进行virtual Monster* createMonster() = 0;// 做父类时析构函数应该为虚函数virtual ~MonsterFactory() {};};// 亡灵类工厂类class UndeadFactor : public MonsterFactory {public:Monster* createMonster() override{// 创建亡灵类怪物Monster* temp = new Undead(300, 50, 80);// return new Undead(300, 50, 80);return temp;}};// 元素类工厂类class ElementFactor : public MonsterFactory {public:Monster* createMonster() override{// 创建元素类怪物Monster* temp = new Element(300, 50, 80);return temp;}};// 机械类工厂类class MechanicFactor : public MonsterFactory {public:Monster* createMonster() override{// 创建机械类怪物Monster* temp = new Mechanic(300, 50, 80);return temp;}};// 全局的用于创建怪物对象的函数,注意形参的类型是工厂父类类型的指针,返回类型是怪物父类的指针Monster* globalCreateMonster(MonsterFactory* factory){return factory->createMonster(); // 该虚函数扮演了多态new的行为,factory指向的具体怪物工厂类不同,创建的怪物对象也不同}// 不想创建太多工厂类,又想封装变化// 创建怪物工厂子类模板template <typename T>class ChildFactory : public MonsterFactory {public:Monster* createMonster() override{return new T(300, 50, 80); // 如果需要不同的值则可以通过createMonster的形参将值传递进来}};void FactorMode(){{// 产生亡灵类怪物MonsterFactory* undeadFactor = new UndeadFactor();Monster* undead = globalCreateMonster(undeadFactor);// 产生元素类怪物MonsterFactory* elementFactor = new ElementFactor();Monster* element = globalCreateMonster(elementFactor);// 产生机械类怪物MonsterFactory* mechanicFactor = new MechanicFactor();Monster* mechanic = globalCreateMonster(mechanicFactor);delete undeadFactor;delete undead;delete elementFactor;delete element;delete mechanicFactor;delete mechanic;}cout << endl;{ // 封装怪物子类ChildFactory<Undead> undeadFactory;Monster* undead = undeadFactory.createMonster();delete undead;}}
定义:定义一个用于创建对象的接口,但由子类决定要实例化的类是哪一个。
- 接口,即 MonsterFactory类中的
createMonster()成员函数,这其实就是个工厂方法,工厂方法模式的名字也是由此而来。 - 子类,即子工厂类 UndeadFactory、MechanicFactory、ElementFactory决定要实例化的类是哪一个。
- 该模式使得某个类Undead、Mechanic、Element的实例化延迟到子类。
一般可以认为,将简单工厂模式的代码经过把工厂类进行抽象改造成符合开闭原则后的代码,就变成了工厂方法模式的代码。
把用 new创建对象集中到某个或者某些工厂类的成员函数中去做的好处是:
- 封装变化:
- 创建对象前需要一些额外的业务代码,可以将这些代码增加到具体的工厂类的
createMonster()函数中。
简单工厂模式把创建对象这件事放到了一个统一的地方来处理,弹性比较差;而工厂方法模式相当于建立了一个程序实现框架,从而让子类来决定对象如何创建。
工厂方法模式往往需要创建一个与产品等级结构(层次)相同的工厂等级结构,这也增加了新类的层次结构和数目。
不想创建太多工厂类,又想封装变化,可以创建怪物工厂子类模板
template <typename T>class ChildFactory : public MonsterFactory {public:virtual Monster* createMonster(){return new T(300, 50, 80); // 如果需要不同的值则可以通过createMonster的形参将值传递进来};};int main(int argc, char* argv[]){ChildFactory<Undead> myFactory;Monster* p10 = myFactory.createMonster();delete p10;}
2.3 类图
三、抽象工厂模式 Abstract Factory
3.1 战斗场景分类范例
3.1.1 功能策划
- 怪物分类:亡灵类,元素类,机械类
- (新增场景)战斗场景分类:沼泽地区,山脉地区,城镇。
- 9类怪物:
- 沼泽地区:亡灵类、元素类、机械类
- 山脉地区:亡灵类、元素类、机械类
- 城镇地区:亡灵类、元素类、机械类
工厂方法模式:一个工厂创建一种类怪物
但如果一个工厂子类能够创建不止一种而是多种具有相同规则的怪物对象,那么就可以有效的减少所创建的工厂子类数量,这就是抽象工厂模式的核心思想。
两个概念:
- 产品等级结构
- 产品族
抽象工厂模式是按照产品族来生产产品(产地相同的用一个工厂来生产)— 一个地点有一个工厂,该工厂负责生产本产地的所有产品。
3.1.2 示例代码
#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:int m_life; // 生命值int m_magic; // 魔法值int m_attack; // 攻击力};// 沼泽地区亡灵类怪物class SwampUndead : public Monster {public:SwampUndead(int life, int magic, int attack): Monster(life, magic, attack){cout << "A swamp undead monster came into the world." << endl;}// 其他代码略...~SwampUndead() { }};// 沼泽地区元素类怪物class SwampElement : public Monster {public:SwampElement(int life, int magic, int attack): Monster(life, magic, attack){cout << "A swamp element monster came into the world." << endl;}// 其他代码略...~SwampElement() { }};// 沼泽地区机械类怪物class SwampMechanic : public Monster {public:SwampMechanic(int life, int magic, int attack): Monster(life, magic, attack){cout << "A swamp mechanic monster came into the world." << endl;}// 其他代码略...~SwampMechanic() { }};// -------------------------------------------------------------------// 山脉亡灵类怪物class MountainUndead : public Monster {public:MountainUndead(int life, int magic, int attack): Monster(life, magic, attack){cout << "A mountain undead monster came into the world." << endl;}// 其他代码略...~MountainUndead() { }};// 山脉元素类怪物class MountainElement : public Monster {public:MountainElement(int life, int magic, int attack): Monster(life, magic, attack){cout << "A mountain element monster came into the world." << endl;}// 其他代码略...~MountainElement() { }};// 山脉机械类怪物class MountainMechanic : public Monster {public:MountainMechanic(int life, int magic, int attack): Monster(life, magic, attack){cout << "A mountain mechanic monster came into the world." << endl;}// 其他代码略...~MountainMechanic() { }};// -------------------------------------------------------------------// 城镇亡灵类怪物class TownUndead : public Monster {public:TownUndead(int life, int magic, int attack): Monster(life, magic, attack){cout << "A town undead monster came into the world." << endl;}// 其他代码略...~TownUndead() { }};// 山脉元素类怪物class TownElement : public Monster {public:TownElement(int life, int magic, int attack): Monster(life, magic, attack){cout << "A town element monster came into the world." << endl;}// 其他代码略...~TownElement() { }};// 山脉机械类怪物class TownMechanic : public Monster {public:TownMechanic(int life, int magic, int attack): Monster(life, magic, attack){cout << "A town mechanic monster came into the world." << endl;}// 其他代码略...~TownMechanic() { }};// -------------------------------------------------------------------// 所有工厂类的父类class MonsterFactory {public:// 创建亡灵类怪物virtual Monster* createMonsterUndead() = 0;// 创建元素类怪物virtual Monster* createMonsterElement() = 0;// 创建机械类怪物virtual Monster* createMonsterMechanic() = 0;// 做父类时析构函数应该为虚函数virtual ~MonsterFactory() { }};// 沼泽地区工厂类class SwapFactory : public MonsterFactory {public:// 创建沼泽地区亡灵类怪物Monster* createMonsterUndead() override{return new SwampUndead(300, 50, 120);};// 创建沼泽地区元素类怪物Monster* createMonsterElement() override{return new SwampElement(200, 80, 110);};// 创建沼泽地区机械类怪物Monster* createMonsterMechanic() override{return new SwampMechanic(400, 0, 90);};~SwapFactory() { }};// 山脉地区工厂类class MountainFactory : public MonsterFactory {public:// 创建山脉地区亡灵类怪物Monster* createMonsterUndead() override{return new MountainUndead(300, 50, 80);};// 创建山脉地区元素类怪物Monster* createMonsterElement() override{return new MountainElement(200, 80, 100);};// 创建山脉地区机械类怪物Monster* createMonsterMechanic() override{return new MountainMechanic(600, 0, 90);};~MountainFactory() { }};// 城镇地区工厂类class TownFactory : public MonsterFactory {public:// 创建城镇地区亡灵类怪物Monster* createMonsterUndead() override{return new TownUndead(300, 50, 120);};// 创建城镇地区元素类怪物Monster* createMonsterElement() override{return new TownElement(200, 80, 110);};// 创建城镇地区机械类怪物Monster* createMonsterMechanic() override{return new TownMechanic(400, 0, 90);};~TownFactory() { }};void abstractFactorMode(){// 多态工厂, 山脉地区的工厂MonsterFactory* mountainFactory = new MountainFactory();// 创建山脉地区的元素类怪物、亡灵类怪物Monster* mountainElementMonster = mountainFactory->createMonsterElement();Monster* mountainUndeadMonster = mountainFactory->createMonsterUndead();// 多态工厂,沼泽地区的工厂MonsterFactory* swampFactory = new SwapFactory();// 创建山脉地区的元素类怪物、亡灵类怪物Monster* swampElementMonster = swampFactory->createMonsterElement();Monster* swampUndeadMonster = swampFactory->createMonsterUndead();delete mountainFactory;delete mountainElementMonster;delete mountainUndeadMonster;delete swampFactory;delete swampElementMonster;delete swampUndeadMonster;}
3.1.3 类图
3.1.4 优缺点
- 增加森林类新场景,怪物种类不变。则只需要增加一个新子工厂比如FactoryForest,符合开闭原则。
- 增加新怪物种类比如龙类,不但要增加三个继承自Monster的子类,还要针对ParentFactory增加新的虚函数接口比如createMonsterDragon,同时各个子工厂类都需要实现createMonsterDragon,这种修改代码的方式来增加新怪物种类,不符合开闭原则,所以增加新怪物的情形不适合抽象工厂模式。
只增加一个产品族则符合开闭原则,只需要增加新工厂子类,这是该模式的优点。但若增加新产品等级结构,需要修改抽象层代码,这是抽象工厂模式的缺点。所以,应避免在产品等级结构不稳定的情况下使用该模式。也就是说,如果游戏中怪物种类(亡灵类,元素类,机械类)比较固定的情况下,更适合使用抽象工厂模式。
3.2 不同厂商生产不同部件范例
3.2.1 功能策划
商品:芭比娃娃:身体(包括头、颈部、躯干、四肢)、衣服、鞋子
- 厂商:中国,日本,美国
要求制作两个芭比娃娃:
- 第一个:身体,衣服,鞋子,全部采用中国厂商制造的部件。
- 第二个:身体采用中国厂商,衣服部件采用日本厂商,鞋子部件采用美国厂商。
3.2.2 示例代码
类的设计思路:
- 将身体,衣服,鞋子 这三个部件实现为抽象类。
- 实现一个抽象工厂,分别用来生产身体、衣服、鞋子这三个部件。
- 针对不同厂商的每个部件实现具体的类以及每个厂商所代表的具体工厂。
```cpp
pragma once
include
using namespace std;
// 身体抽象类 class Body { public: virtual void getName() = 0; virtual ~Body() {}; }; // 衣服抽象类 class Clothes { public: virtual void getName() = 0; virtual ~Clothes() {}; }; // 鞋子抽象类 class Shoes { public: virtual void getName() = 0; virtual ~Shoes() {}; };
// ———————————————————————————-
// 抽象工厂类 class AbstractFactory { public: // 所创建的部件应该稳定的保持这三个部件,才适合抽象工厂模式 virtual Body createBody() = 0; // 创建身体 virtual Clothes createClothes() = 0; // 创建衣服 virtual Shoes* createShoes() = 0; // 创建鞋子 virtual ~AbstractFactory() {}; };
// ———————————————————————————-
// 芭比娃娃类 class BarbieDoll { public: // 构造函数 BarbieDoll(Body body, Clothes clothes, Shoes* shoes) { m_body = body; m_clothes = clothes; m_shoes = shoes; } // 组装芭比娃娃 void assemble() { cout << “Successfully assembled the Barbie doll.” << endl; m_body->getName(); m_clothes->getName(); m_shoes->getName(); }
private: Body m_body; Clothes m_clothes; Shoes* m_shoes; };
// 中国厂商实现的三个部件及工厂 class ChinaBody : public Body { public: void getName() override { cout << “Body made in China” << endl; } }; class ChinaClothes : public Clothes { public: void getName() override { cout << “Clothes made in China” << endl; } }; class ChinaShoes : public Shoes { public: void getName() override { cout << “Shoes made in China” << endl; } }; class ChinaFactory : public AbstractFactory { Body createBody() override { // 创建身体 return new ChinaBody(); }; Clothes createClothes() override { // 创建衣服 return new ChinaClothes(); } Shoes* createShoes() override { // 创建鞋子 return new ChinaShoes(); } ~ChinaFactory() {}; };
// 日本厂商实现的三个部件及工厂 class JapanBody : public Body { public: void getName() override { cout << “Body made in Japan” << endl; } }; class JapanClothes : public Clothes { public: void getName() override { cout << “Clothes made in Japan” << endl; } }; class JapanShoes : public Shoes { public: void getName() override { cout << “Shoes made in Japan” << endl; } }; class JapanFactory : public AbstractFactory { Body createBody() override { // 创建身体 return new JapanBody(); }; Clothes createClothes() override { // 创建衣服 return new JapanClothes(); } Shoes* createShoes() override { // 创建鞋子 return new JapanShoes(); } ~JapanFactory() {}; };
// 美国厂商实现的三个部件及工厂 class AmericaBody : public Body { public: void getName() override { cout << “Body made in America” << endl; } }; class AmericaClothes : public Clothes { public: void getName() override { cout << “Clothes made in America” << endl; } }; class AmericaShoes : public Shoes { public: void getName() override { cout << “Shoes made in America” << endl; } }; class AmericaFactory : public AbstractFactory { Body createBody() override { // 创建身体 return new AmericaBody(); }; Clothes createClothes() override { // 创建衣服 return new AmericaClothes(); } Shoes* createShoes() override { // 创建鞋子 return new AmericaShoes(); } ~AmericaFactory() {}; };
void abstractFactorMode() { { // 第一个芭比娃娃: 身体,衣服,鞋子,全部采用中国厂商制造的部件 // 1.创建一个中国工厂 AbstractFactory chinaFactory = new ChinaFactory(); // 2. 创建中国生产的部件 Body body = chinaFactory->createBody(); Clothes clothes = chinaFactory->createClothes(); Shoes shoes = chinaFactory->createShoes(); // 3. 创建芭比娃娃 BarbieDoll* barbieDoll = new BarbieDoll(body, clothes, shoes); barbieDoll->assemble();
delete chinaFactory;delete body;delete clothes;delete shoes;delete barbieDoll;}cout << endl;{ // 第二个芭比娃娃: 身体采用中国厂商,衣服部件采用日本厂商,鞋子部件采用美国厂商。// 1.创建工厂AbstractFactory* chinaFactory = new ChinaFactory();AbstractFactory* japanFactory = new JapanFactory();AbstractFactory* americaFactory = new AmericaFactory();Body* body = chinaFactory->createBody();Clothes* clothes = japanFactory->createClothes();Shoes* shoes = americaFactory->createShoes();BarbieDoll* barbieDoll = new BarbieDoll(body, clothes, shoes);barbieDoll->assemble();delete chinaFactory;delete japanFactory;delete americaFactory;delete body;delete clothes;delete shoes;delete barbieDoll;}
}
2.2.3 类图
工厂方法模式和抽象工厂模式区别:
- 工厂方法模式:一个工厂生产一个产品
- 抽象工厂模式:一个工厂生产多个产品(产品族)
抽象工厂模式的定义(实现意图):提供一个接口(AbstractFactory),
让该接口负责创建一系列相关或者相互依赖的对象(Body,Clothes,Shoes),而无需指定他们具体的类。
三种工厂模式的总结:
- 从代码实现复杂度:
- 从需要的工厂数量上:
- 从实际应用上:
