C++设计模式_创建型模式_工厂方法模式

目录

C++设计模式_创建型模式_工厂方法模式

一、简单工厂模式

[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 从实际项目角度:小项目用简单工厂模式,中大型项目:工厂模式;大型项目:抽象工厂模式。

相关推荐
ke_wu7 小时前
结构型设计模式
开发语言·设计模式·组合模式·简单工厂模式·工厂方法模式·抽象工厂模式·装饰器模式
ke_wu19 小时前
模板方法、观察者模式、策略模式
观察者模式·简单工厂模式·策略模式·模板方法模式
码农爱java4 天前
设计模式--抽象工厂模式【创建型模式】
java·设计模式·面试·抽象工厂模式·原理·23种设计模式·java 设计模式
思忖小下5 天前
梳理你的思路(从OOP到架构设计)_设计模式Factory Method模式
设计模式·工厂方法模式·eit
霁月风5 天前
设计模式——工厂方法模式
c++·设计模式·工厂方法模式
NorthCastle5 天前
设计模式-创建型模式-简单工厂模式详解
设计模式·简单工厂模式
越甲八千7 天前
简单工厂模式和策略模式的异同
简单工厂模式·策略模式
澄澈i7 天前
设计模式学习[13]---抽象工厂模式+简单工厂+工厂方法模式回顾
学习·设计模式·抽象工厂模式
重生之我在字节当程序员8 天前
解释工厂模式
开发语言·c++·简单工厂模式
33三 三like9 天前
第三章、简单工厂模式
简单工厂模式