C++11 设计模式3. 工厂方法模式

简单工厂模式的遗留问题

    //从上面的代码可以看到,简单工厂模式确实实现了new 出来具体对象, 和 业务逻辑的分离,
    //但是不符合 "开闭原则"
    //"开闭原则"说的是代码扩展性问题——对扩展开放,对修改关闭(封闭);
    //假设过了两天,策划找到我们说:加一种怪物,新怪物类型:M_Beast(野兽类)
    //那我们要怎么改呢?首先肯定是加一个 M_Beast类了,继承Monster
    //然后MonsterFactory 中改动 createMonster方法完成。
    //很显然,我们要改动到原先的 createMonster 方法,这是违反了 "开闭原则的"。
    //那么如何改动才合理呢?这就要用到 "工厂方法" 模式

解决方案:工厂方法 模式

工厂方法(Factory Method)模式:简称工厂模式或者多态工厂模式。
    //与简单工厂模式比,灵活性更强,实现也更加复杂,引入更多的新类。
    //M_UndeadFactory,M_ElementFactory,M_MechanicFactory类,有一个共同的父类M_ParFactory(工厂抽象类):
      //符合开闭原则,付出的代价是需要新增加多个新的工厂类。
    //定义(实现意图):定义一个用于创建对象的接口(M_ParFactory类中的createMonster成员函数,这其实就是个工厂方法,工厂方法模式的名字也是由此而来),
      //但由子类(M_UndeadFactory、M_ElementFactory、M_MechanicFactory)决定要实例化的类是哪一个。
      //该模式使得某个类(M_Undead、M_Element、M_Mechanic)的实例化延迟到子类(M_UndeadFactory、M_ElementFactory、M_MechanicFactory)。
    //出现新怪物类型:M_Beast(野兽类)。
    //一般可以认为,将简单工厂模式的代码经过把工厂类进行抽象改造成符合开闭原则后的代码,就变成了工厂方法模式的代码。
    

代码实现



#include <iostream>
using namespace std;

//(1)简单工厂(Simple Factory)模式
//策划:亡灵类怪物,元素类怪物,机械类怪物:都有生命值,魔法值,攻击力三个属性。
//Monster作为父类,M_Undead(亡灵类),M_Element(元素类怪物),M_Mechanic(机械类怪物)。

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;
	};

	//M_Undead(亡灵类)
	class M_Undead :public Monster {
	public:
		M_Undead(int life, int magic, int attack) :Monster(life, magic, attack) {
			cout << "创建了一个亡灵类 life = " << m_life << "  magic = " << m_magic << "  attack = " << m_attack << endl;
		}
	};

	//M_Element(元素类怪物)
	class M_Element :public Monster {
	public:
		M_Element(int life, int magic, int attack) :Monster(life, magic, attack) {
			cout << "创建了一个元素类怪物 life = " << m_life << "  magic = " << m_magic << "  attack = " << m_attack << endl;
		}
	};

	//M_Mechanic(机械类怪物)
	class M_Mechanic :public Monster {
	public:
		M_Mechanic(int life, int magic, int attack) :Monster(life, magic, attack) {
			cout << "创建了一个机械类怪物 life = " << m_life << "  magic = " << m_magic << "  attack = " << m_attack << endl;
		}
	};

	//所有工厂类的父类
	class M_ParFactory
	{
	public:
		virtual Monster* createMonster() = 0; //具体的实现在子类中进行
		virtual ~M_ParFactory() {} //做父类时析构函数应该为虚函数
	};
	//每一个具体的类都有自己的工厂
	class Undead_Factory :public M_ParFactory {
	public:
		Monster* createMonster() {
			return new M_Undead(111, 222, 333);
		}
	};

	class Element_Factory :public M_ParFactory {
	public:
		Monster* createMonster() {
			return new M_Element(444, 555, 666);
		}
	};

	class Mechanic_Factory :public M_ParFactory {
	public:
		Monster* createMonster() {
			return new M_Mechanic(777, 888, 999);
		}
	};

	//这里要有一个方法能够返回需要的具体的Monster,参数为M_ParFactory类型指针
	Monster * g_createMonster_use_factory_method(M_ParFactory * parfactory) {
		return parfactory->createMonster();
	}

};


void testfactorymethod() {
	_namespace1::M_ParFactory *par1 = new _namespace1::Undead_Factory();
	_namespace1::Monster *pmon1 = _namespace1::g_createMonster_use_factory_method(par1);

	_namespace1::M_ParFactory *par2 = new _namespace1::Element_Factory();
	_namespace1::Monster *pmon2 = _namespace1::g_createMonster_use_factory_method(par2);

	_namespace1::M_ParFactory *par3 = new _namespace1::Mechanic_Factory();
	_namespace1::Monster *pmon3 = _namespace1::g_createMonster_use_factory_method(par3);

	delete par1;
	delete par2;
	delete par3;
	delete pmon1;
	delete pmon2;
	delete pmon3;

}


int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口

	//"工厂方法" 模式
	testfactorymethod();


	std::cout << "Hello World!\n";
}

简单工厂模式 和 工厂方法模式 对比


    //简单工厂模式把创建对象这件事放到了一个统一的地方来处理,弹性比较差。而工厂方法模式相当于建立了一个程序实现框架,从而让子类来决定对象如何创建。
    //工厂方法模式往往需要创建一个与产品等级结构(层次)相同的工厂等级结构,这也增加了新类的层次结构和数目。

使用模版

//全局的用于创建怪物对象的函数,注意形参的类型是工厂父类类型的指针,返回类型是怪物父类类型的指针
	Monster* Gbl_CreateMonster(M_ParFactory* factory,int canshu1,int canshu2,int canshu3)
	{
		return  factory->createMonster1(canshu1, canshu2, canshu3); //createMonster虚函数扮演了多态new的行为,factory指向的具体怪物工厂类不同,创建的怪物对象也不同。
	}

	//-------------------
	//不想创建太多工厂类,又想封装变化
	//创建怪物工厂子类模板
	template <typename T>
	class M_ChildFactory :public M_ParFactory
	{
	public:
		virtual Monster* createMonster1(int canshu1, int canshu2, int canshu3)
		{
			return new T(canshu1, canshu2, canshu3); //如果需要不同的值则可以通过createMonster的形参将值传递进来
		}
	};

工厂方法模式的UML图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/540190.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法设计与分析实验报告c++实现(TSP问题、哈夫曼编码问题、顾客安排问题、最小生成树问题、图着色问题)

一、实验目的 1&#xff0e;加深学生对贪心算法设计方法的基本思想、基本步骤、基本方法的理解与掌握&#xff1b; 2&#xff0e;提高学生利用课堂所学知识解决实际问题的能力&#xff1b; 3&#xff0e;提高学生综合应用所学知识解决实际问题的能力。 二、实验任务 用贪心算…

C# 两种方法截取活动窗口屏幕,实现窗体截图

方法1&#xff0c;截屏内容仅包括活动窗口界面&#xff0c;而方法2是从屏幕范围取图&#xff0c;截屏内容会包括屏幕上所有内容。例如有一些程序在桌面顶层显示半透明的悬浮窗&#xff0c;用方法2截屏就会包括这些内容&#xff0c;并不是单纯的活动窗口内容。 方法1&#xff0c…

开源代码分享(19)-配电网孤岛优化划分方法

参考文献&#xff1a; DING Tao, LIN Yanling, LI Gengfeng, et al. A new model for resilient distribution systems by microgrids formation[J]. IEEE Transactions on Power Systems, 2017, 32(5): 4145-4147. 1.基本原理 通过分布式电源&#xff08;DGs&#xff09;形…

蓝桥杯 前一晚总结 模板 新手版

《准备实足&#xff0c;冲冲冲 省一》https://www.yuque.com/lenyan-svokd/hi7hp2/hfka297matrtsxy2?singleDoc# 《准备实足&#xff0c;冲冲冲 省一》 #include<bits/stdc.h> // 包含标准库头文件using namespace std; using ll long long; // 定义 long long 数据类…

218基于matlab的有限差分法求解泊松方程

基于matlab的有限差分法求解泊松方程&#xff0c;采用SOR超松弛迭代法。模型采用方形区域&#xff0c;划分网格数为100*100&#xff0c;网格数可以很方便的更改。程序已调通&#xff0c;可直接运行。 218有限差分法 泊松方程 SOR超松弛迭代法 - 小红书 (xiaohongshu.com)

基于React封装Handsontable并兼容antd

背景 其实Handsontable官方也提供了React的版本&#xff0c;但是官方的版本再编辑和渲染的时候并不能够很好的嵌入第三方的组件库。这就导致了&#xff0c;使用了Handsontable就没有办和普通的react项目一样轻松引用其他第三方组件。因此对其react的版本进行了二次的封装&#…

定制个性化的 openEuler 系统镜像:打造独特的安装体验

前言 标准的操作系统镜像可能无法完全满足特定用户群体或特定应用场景的需求。通过定制化&#xff0c;可以根据具体需求预装特定软件、配置特定网络设置&#xff0c;甚至设置特定的用户权限&#xff0c;以确保系统能够满足用户的需求。定制化系统镜像可以优化安装流程&#xf…

PandasAI的应用与实战解析(二):PandasAI使用流程与功能介绍

文章目录 1.使用PandasAI进行开发的流程2.配置文件解析3.支持的数据库类型4.支持的LLMs5.其他 PandasAI这个工具最突出的优点就是通过结合了Pandas和生成式LLMs&#xff0c;极大地为开发人员降低了工作量。 传统的开发调用流程&#xff08;数据分析相关&#xff09;&#xff1a…

(UDP)其他信息: 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。

“System.Net.Sockets.SocketException”类型的异常在 mscorlib.dll 中发生&#xff0c;但未在用户代码中进行处理其他信息: 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。这个异常表示端口已经被占用了&#xff0c;需要释放端口或者使用其他端口来建立连接。您可以…

CLion 2024:为Mac与Win打造的卓越跨平台集成开发环境

CLion 2024作为一款跨平台IDE&#xff0c;CLion 2024不仅完美支持Mac和Windows两大操作系统&#xff0c;更在细节之处展现了其出色的跨平台兼容性。无论你是在Mac的优雅界面下工作&#xff0c;还是在Windows的实用环境中编程&#xff0c;CLion 2024都能为你提供一致且流畅的开发…

如何使用 Grafana 监控文件系统状态

当 JuiceFS 文件系统部署完成并投入生产环境&#xff0c;接下来就需要着手解决一个非常重要的问题 —— 如何实时监控它的运行状态&#xff1f;毕竟&#xff0c;它可能正在为关键的业务应用或容器工作负载提供持久化存储支持&#xff0c;任何小小的故障或性能下降都可能造成不利…

ES6: set和map数据结构以及使用场景

ES6:set和map数据结构 一、Set 数据结构&#xff1a;二、使用场景&#xff1a;使用Set 进行去重三、Map 数据结构四、使用场景&#xff1a;使用Map进行树型数据懒加载刷新五、Set和Map的区别六、Map、Set的实际使用场景 Set 和 Map 是 ES6 中引入的两种新的数据结构&#xff0c…

设计模式代码实战-装饰者模式

1、问题描述 小明喜欢品尝不同口味的咖啡&#xff0c;他发现每种咖啡都可以加入不同的调料&#xff0c;比如牛奶、糖和巧克力。他决定使用装饰者模式制作自己喜欢的咖啡。 请设计一个简单的咖啡制作系统&#xff0c;使用装饰者模式为咖啡添加不同的调料。系统支持两种咖啡类型…

ANSYS Electromagnetics Suite 2023 R2 三维电磁(EM)仿真软件下载

Ansys家最新的三维电磁&#xff08;EM&#xff09;仿真软件ANSYS Electromagnetics Suite 2023 R2日前发布了&#xff0c;老wu这次分享得有点晚 &#xffe3;ω&#xffe3;&#xff0c;现在已经将资源上传到了网盘供大家免费下载&#xff0c;同时&#xff0c;为了让大家都能与…

企业航拍VR全景视频展示仿如上门参观

360度VR全景视频因其广阔的视野和身临其境的体验&#xff0c;无论再房产楼盘的精致呈现&#xff0c;旅游景点的全景漫游&#xff0c;还是校园风光的生动展示&#xff0c;都成为企业商户的首选。 360度vr全景视频编辑软件是深圳VR公司华锐视点提供多种常见的三维仿真场景供选择&…

防火墙操作!

当小编在Linux服务器上部署好程序以后&#xff0c;但是输入URL出现下述情况&#xff0c;原来是防火墙的原因&#xff01;&#xff01; 下面是一些防火墙操作&#xff01; 为保证系统安全&#xff0c;服务器的防火墙不建议关闭&#xff01;&#xff01; 但是&#xff0c;我们可…

最优算法100例之44-不用加减乘除做加法

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 不用加减乘除做加法 题解报告 最优解法:使用异或 1)异或是查看两个数哪些二进制位只有一个为1,这些是非进位位,可以直接…

[python]cartopy安装后测试代码

测试环境&#xff1a; anaconda3python3.11 cartopy0.23.0 测试代码&#xff1a; # 导入所需的库 import matplotlib as mpl import matplotlib.pyplot as plt import cartopy.crs as ccrs# 创建画布以及ax fig plt.figure() ax fig.add_subplot(111, projectionccrs.Pla…

Android - 安卓概述

什么是安卓? Android 是一种基于 Linux 的开源操作系统&#xff0c;适用于智能手机和平板电脑等移动设备。 Android 是由 Google 和其他公司领导的 Open Handset Alliance 开发的。 Android 为移动设备的应用程序开发提供了统一的方法&#xff0c;这意味着开发人员只需为 And…

React + three.js 实现人脸动捕与3D模型表情同步

系列文章目录 React 使用 three.js 加载 gltf 3D模型 | three.js 入门React three.js 3D模型骨骼绑定React three.js 3D模型面部表情控制React three.js 实现人脸动捕与3D模型表情同步 示例项目(github)&#xff1a;https://github.com/couchette/simple-react-three-facia…