当前位置: 首页 > 编程日记 > 正文

设计模式(2)工厂方法模式(Factory Method)

设计模式(0)简单工厂模式

设计模式(1)单例模式(Singleton)

源码地址

0 工厂方法模式简介

0.0 工厂方法模式定义

工厂方法模式是在简单工厂模式基础上,为解决更复杂的对象创建问题而衍生进化出来的一种创建型模式。

工厂方法模式的核心思想是定义一个用于创建对象的接口,让其子类去决定去实例化哪个具体类的对象,工厂方法模式可以使一个类的实例化动作延迟到其子类。

工厂方法模式结构图如下

1

0.1 工厂方法模式应用场景

还接着祭坛生产英雄的示例,我们已经在简单工厂模式一文中通过创建简单工厂方法类,来实现暗夜精灵种族4个英雄的创建

/// <summary>/// 创建英雄的静态方法/// </summary>/// <param name="heroName">英雄名称</param>/// <returns></returns>public static IHero CreateHero(string heroName){switch (heroName){case "DH":return new DH();case "WD":return new WD();case "KOG":return new KOG();case "POM":return new POM();default:return null;}}

假设现在我们要创建不死族的英雄怎么办呢,如果依然使用简单工厂方法类,则首先需要实现不死族四个英雄类。

/// <summary>
/// 死亡骑士
/// </summary>
public class DK : IHero
{/// <summary>/// 秀出自己的技能/// </summary>public void ShowSkills(){Console.WriteLine("我是死亡骑士,我会死亡缠绕、死亡契约、邪恶光环和操纵死尸。");}
}
/// <summary>
/// 巫妖
/// </summary>
public class Lich : IHero
{/// <summary>/// 秀出自己的技能/// </summary>public void ShowSkills(){Console.WriteLine("我是巫妖,我会霜冻新星、寒冰甲、黑暗仪式和死亡凋零。");}
}
/// <summary>
/// 地穴领主
/// </summary>
public class DL : IHero
{/// <summary>/// 秀出自己的技能/// </summary>public void ShowSkills(){Console.WriteLine("我是地穴领主,我会穿刺、刺盾、腐蚀甲虫和蝗群。");}
}
/// <summary>
/// 恐惧魔王
/// </summary>
public class CL : IHero
{/// <summary>/// 秀出自己的技能/// </summary>public void ShowSkills(){Console.WriteLine("我是恐惧魔王,我会腐臭群蜂、睡眠、吸血光环、地狱火。");}
}

然后需要修改工厂方法,增加switch语句中的类型,将不死族四个英雄创建逻辑添加进去。

/// <summary>
/// 创建英雄的静态方法
/// </summary>
/// <param name="heroName">英雄名称</param>
/// <returns></returns>
public static IHero CreateHero(string hero
{switch (heroName){//暗夜精灵case "DH":return new DH();case "WD":return new WD();case "KOG":return new KOG();case "POM":return new POM();// 不死族case "DK":return new DK();case "Lich":return new Lich();case "CL":return new CL();case "DL":return new DL();default:return null;}
}

还有兽族及人族,也需要如此修改。到此我们会感觉存在有以下问题

1、随着英雄的增多,简单工厂类需要反复修改。

2、简单工厂类过于庞大,职责混乱,负责了四个种族所有英雄的创建,而实际上,玩家在进入游戏时已经选好了自己的种族,只有可能创建所选种族的英雄。

我们到了这里,首先要想到的是,既然四个种族,分别有自己的祭坛,产生改种族的英雄,我们应该将简单工厂类按照种族进行职责拆分,此时参考上面提到的工厂方法模式定义以及结构图,我们会发现,现在是到了工厂方法模式出场的时候了。

1 工厂方法模式详解

1、提炼工厂方法接口

将原来的简单工厂类,进一步提炼为一个工厂方法接口,其包含一个名为CreateHero的接口。

/// <summary>
/// 工厂方法接口
/// </summary>
public interface IFactory
{/// <summary>/// 创建英雄的方法/// </summary>/// <param name="heroName">英雄名称</param>/// <returns></returns>IHero CreateHero(string heroName);
}

2、实现四个种族的工厂方法

四个种族创建英雄的工厂方法继承自工厂方法接口,实现CreateHero。

/// <summary>
/// 暗夜精灵种族英雄工厂类
/// </summary>
public class NEFactory : IFactory
{/// <summary>/// 创建英雄的静态方法/// </summary>/// <param name="heroName">英雄名称</param>/// <returns></returns>public IHero CreateHero(string heroName){switch (heroName){//暗夜精灵case "DH":return new DH();case "WD":return new WD();case "KOG":return new KOG();case "POM":return new POM();default:return null;}}
}
/// <summary>
/// 不死族英雄工厂类
/// </summary>
public class UDFactory : IFactory
{/// <summary>/// 创建英雄的静态方法/// </summary>/// <param name="heroName">英雄名称</param>/// <returns></returns>public IHero CreateHero(string heroName){switch (heroName){// 不死族case "DK":return new DK();case "Lich":return new Lich();case "CL":return new CL();case "DL":return new DL();default:return null;}}
}

3、客户端调用

static void Main(string[] args)
{IFactory factory = new NEFactory();  // 初始化一个暗夜精灵族的英雄工厂Console.WriteLine("我在开局时选择了暗夜精灵族,我的首发英雄是DH。");IHero dh = factory.CreateHero("DH");dh.ShowSkills();factory = new UDFactory();  // 初始化一个不死族的英雄工厂Console.WriteLine("我在开局时选择了不死族,我的首发英雄是DK。");IHero dk = factory.CreateHero("DK");dk.ShowSkills();Console.ReadLine();
}

1

4、通过反射实例化具体的工厂方法类

在实际应用中跟上面不同种族创建英雄的例子类似,一般在系统启动时就已经确定要使用哪种方法实例化工厂方法类,通常我们可以将工厂类的实例化通过配置文件的方式确定,从而避免源码的修改。

string factoryName = ConfigurationManager.AppSettings["FactoryName"]; // 读取配置文件
IFactory factory = (IFactory)Assembly.Load("FactoryMethodPattern").CreateInstance("FactoryMethodPattern." + factoryName); // 实例化配置的工厂方法类

2 总结

工厂方法模式具有以下优点

1、更容易对现有功能进行扩展,如果有新的需求,只需要实现一个相应的工厂方法实现类即可,无需修改现有代码。

2、不同工厂方法类,实现了单一职责的设计原则。

工厂方法模式的缺点

由于具体的对象由具体指定的工厂方法类创建,导致具体产品和工厂方法类之间具有较强的耦合性

转载于:https://www.cnblogs.com/fonour/p/7055737.html

相关文章:

基于Matlab的遗传算法优化BP神经网络在非线性函数拟合中的应用

本微信图文详细介绍了遗传算法优化BP神经网络初始权值阈值的过程&#xff0c;并通过实例说明该优化能够提升BP神经网络的预测精确程度。

android 加载h5页面部分机型滑动卡顿回弹_网易爆款H5 的交互方法参考

在早些年&#xff0c;H5其实更像是手机上的PPT&#xff0c;只支持点击、滑动这些基础手势操作。以内容展示为主&#xff0c;交互形式为辅。但到了今天&#xff0c;H5的玩法已经有了质的突破。不仅交互形式超多&#xff0c;形式与内容也能紧密结合&#xff0c;产生11大于2的效果…

使用SDL打造游戏世界之入门篇 - 1

来源&#xff1a;天极开发 作者&#xff1a;维维编译 出处&#xff1a;巧巧读书 2007-07-17 进入讨论组 简介 Simple DirectMedia Layer, 简称SDL&#xff0c;是一个自由的跨平台的多媒体开 发包&#xff0c;主要通过OpenGL和2D视频帧缓冲(framebuffer)提供对音频、键盘、鼠标…

RBAC新解 - 基于资源的权限管理

1、什么是角色 当说到程序的权限管理时&#xff0c;人们往往想到角色这一概念。角色是代表一系列可执行的操作或责任的实体&#xff0c;用于限定你在软件系统中能做什么、不能做什么。用户帐号往往与角色相关联&#xff0c;因此&#xff0c;一个用户在软件系统中能做什么取决于…

《C#精彩实例教程》小组阅读07 -- C#字符与字符串

本微信图文详细介绍了C#中的字符与字符串。

syslog打印不带等级_printk的日志级别和控制台级别

printk根据日志级别(loglevel)对消息进行分类。日志级别用宏定义&#xff0c;日志级别宏展开为一个字符串&#xff0c;在编译时由预处理器将它和消息文本拼接成一个字符串&#xff0c;因此printk 函数中日志级别宏和格式字符串间不能有逗号。下面是两个printk的例子&#xff0c…

《C#精彩实例教程》小组阅读08 -- C#流程控制语句

本微信图文详细介绍了C#的流程控制语句。

ASPJPEG缩略图生成函数

好久没有发文章&#xff0c;贴一段代码出来晒晒&#xff01;一段aspjpeg组件生成缩略图的代码&#xff0c;有4种生成方式&#xff0c;建议用最后一种&#xff0c;生成的缩略图最清晰而且不会拉伸、变形&#xff01;做图片生成最好不过&#xff01;// 缩略图生成函数 Code By S…

java面试题收集

2019独角兽企业重金招聘Python工程师标准>>> 1.什么是B/S架构&#xff1f;什么是C/S架构 B/S(Browser/Server)&#xff0c;浏览器/服务器程序 C/S(Client/Server)&#xff0c;客户端/服务端&#xff0c;桌面应用程序 2.你所知道网络协议有那些&#xff1f; HTTP&…

mobile还有人用吗 spring_话说,苹果手机语音备忘录功能还有人用吗?

hi&#xff0c;各位&#xff0c;苹果手机自带的语音备忘录功能还有人在用吗&#xff1f;前两天&#xff0c;有小伙伴在后台留言问&#xff1a;“苹果手机语音备忘录怎么恢复&#xff1f;”小编一时还有些恍惚“它是什么&#xff0c;手机上有吗&#xff1f;”&#xff0c;好在通…

MVC5 + EF6 完整入门教程三

期待已久的EF终于来了。 学完本篇文章&#xff0c;你将会掌握基于EF数据模型的完整开发流程。 本次将会完成EF数据模型的搭建和使用。 基于这个模型&#xff0c;将之前的示例添加数据库查询验证功能。 文章提纲 概述 & 要点 详细步骤 总结 概述 & 要点 下面是本文要点&…

Matlab编程与数据类型 -- 内联函数

本微信图文详细介绍了Matlab中的内联函数。

优化营商环境建议个人_优化营商环境的几点建议(三)

优化临沂的营商环境&#xff0c;重点是做好招商引资的后续环境优化&#xff01;事关一个地区的财税收入&#xff0c;所以放眼全国&#xff0c;招商引资到哪里都是重点工作。早在2018年4月16日&#xff0c;临沂就召开了新旧动能转换暨开放型经济、招商引资工作动员大会&#xff…

基于Matlab的神经网络结合遗传算法在非线性函数极值寻优中的应用

本微信图文利用神经网络进行非线性函数数据的拟合并通过遗传算法对训练后的神经网络进行非线性函数极值寻优。

十分钟成为 Contributor 系列 | 为 TiDB 重构 built-in 函数

2019独角兽企业重金招聘Python工程师标准>>> 这是十分钟成为 TiDB Contributor 系列的第二篇文章&#xff0c;让大家可以无门槛参与大型开源项目&#xff0c;感谢社区为 TiDB 带来的贡献&#xff0c;也希望参与 TiDB Community 能为你的生活带来更多有意义的时刻。 …

研究生要这样度过!(转)

研究生要这样度过&#xff01; 首先要知道研究生期间做什么&#xff1f;我认为研究生期间学生应该学三件事情&#xff1a; 1&#xff09;建立合理的知识结构&#xff1a;尽量广地涉猎学科基本知识&#xff0c;尽量深地了解所研究领域的 方方面面、过去和现在 2&#xff09;掌握…

后端开发面试自我介绍_字节跳动暑期实习后端开发面试经历

字节跳动后端实习是什么&#xff0c;字节跳动后端实习面试流程是怎样&#xff1f;今天小编就来帮助大家了解一下字节跳动后端实习面试到底有什么内容。&#xff08;好了不皮了&#xff0c;开始正文&#xff09;字节的面试流程总的来说还是挺享受的&#xff0c;和面试官两人的思…

《C#精彩实例教程》小组阅读09 -- C#数组与集合

本微信图文详细介绍了C#的数组与集合。

Oracle执行计划突变诊断之统计信息收集问题

Oracle执行计划突变诊断之统计信息收集问题1. 情形描述DB version&#xff1a;11.2.0.4WITH SQL1 AS(SELECT LAC,CI,TO_NUMBER(C.LONGITUDE) LONGITUDE,TO_NUMBER(C.LATITUDE) LATITUDEFROM MB_SYS_CELL_INFO CWHERE C.CONTY_NAME 道孚县), SQL2 AS(SELECT DISTINCT IMSI, LA…

安装gym库_强化学习Gym库学习实践(一)

最近看了一篇研究方向相关的文章&#xff0c;介绍了一种DQN的应用&#xff0c;感觉还挺新鲜的。想着把这篇文章复现出来&#xff0c;就开始学习强化学习的相关知识&#xff0c;作为一名小白&#xff0c;这一路走的可是真的十分艰难&#xff08;我太菜了啊&#xff01;&#xff…

VS2005编译QT4.8.2

为什么要编译&#xff1f; 因为安装安装版的QT4.8.2&#xff0c;vs2005编译报错。 1.下载QT4.8.2&#xff0c;qt-everywhere-opensource-src-4.8.2.zip&#xff0c;下载vs-AddIn1.1.11. 2.解压QT源码包到C盘&#xff0c; 这里路径为 c:\qt\4.8.2\。 3.配置系统环境变量&#xf…

Don’t Use the Win32 API PostThreadMessage() to Post Messages to UI Threads(翻译)

大龙的博客C博客 | 首页 | 发新随笔 | 发新文章 | 联系 | 聚合 | 管理 Don’t Use the Win32 API PostThreadMessage() to Post Messages to UI Threads(翻译) Don’t Use the Win32 API PostThreadMessage() to Post Messages to UI Threads不要用Win32 API PostThreadMessage…

Matlab编程与数据类型 -- 文本M文件

本微信图文详细介绍了Matlab中的文本M文件。

安卓x86_Android:虚拟机体验基于安卓10的BlissOS V12.2 Android X86版

我是科技鲁工&#xff0c;今天带来基于Android10的x86版本的Bliss os的安装体验。喜欢的朋友可以关注支持一下。Bliss OS是一个基于Android x86项目的开源操作系统&#xff0c;能让您在PC电脑或平板电脑设备上运行最新的Android 10操作系统。该系统基于AOSP(Android开放源代码项…

《C#精彩实例教程》小组阅读10 -- C#属性与方法

本微信图文详细介绍了C#的属性与方法。

JavaScript中几个重要的知识点(1) ---- 面向对象

JavaScript中几个最重要的大知识点 面向对象DOM事件异步交互ajax面向对象 在JS中可以把任意的引用和变量都看成是一个对象。面向对象的主要三个表现形式&#xff1a; 封装继承多态1. 封装 1.1 单例模式 var obj{name: "sam",age: 12,method: function(){var objNamet…

scrollLeft,scrollWidth,clientWidth,offsetWidth到底指的哪到哪的距离

轉自:http://www.cnblogs.com/mrhgw/archive/2006/11/08/553737.html 补充&#xff1a; scrollHeight: 获取对象的滚动高度。 scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离 scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的…

连接服务器_命令行连接FTP服务器

Windows下: 打开命令行窗口,输入 ftp,进入ftp命令模式: 输入 open ip地址 端口,进入ftp服务器,如open 172.16.3.77 2121。如下图: 输入Windows下的用户名,然后输入密码(注意:密码是不显示的,输入用户名密码不能时间太长,否则连接断掉)。 查看ftp服务器中的文件,输…

mapreduce作业reduce被大量kill掉

之前有一段时间。我们的hadoop2.4集群压力非常大。导致提交的job出现大量的reduce被kill掉。同样的job执行时间比在hadoop0.20.203上面长了非常多。这个问题事实上是reduce 任务启动时机的问题&#xff0c;因为yarn中没有map slot和reduce slot的概念&#xff0c;且ResourceMan…

Matlab编程与数据类型 -- M文件的编辑和存储

本微信图文详细介绍了Matlab中M文件的编辑和存储。