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

news/2024/7/8 2:21:55

设计模式(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


http://lihuaxi.xjx100.cn/news/240525.html

相关文章

百练,4103,踩方格

百练&#xff0c;4103&#xff0c;踩方格 普通做法&#xff1a;&#xff08;也可以找规律&#xff09; #include #include//要调用memset函数&#xff0c;头文件 using namespace std; int visited[50][50];//开辟50*50的方格 int num0;//num为方案数 void ways(int i,int j,i…

模糊推理 控制 易于实现_代码“易于推理”是什么意思?

模糊推理 控制 易于实现by Preethi Kasireddy通过Preethi Kasireddy 代码“易于推理”是什么意思&#xff1f; (What does it mean when code is “easy to reason about”?) You’ve probably heard the expression “easy to reason about” enough times to make your ear…

sendmail服务器配置过程中出现的一些错误和解决办法

sendmail服务器配置过程中出现的错误和解决办法 以前在做实验的过程中总结和写的一些教程的一些资料&#xff0c;一直没时间发布到博客上面&#xff0c;五一到了&#xff0c;终于有点时间发布啦&#xff01;关于Linux上面还会有RHCE系列的学习笔记发表 1、rpm包不能正常卸载&am…

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

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

java配置

对于现在学习java的同学来说&#xff0c;还是安装12版本比较好&#xff0c;安装也比较&#xff08;是非常方便跟7比起来&#xff09;方便&#xff0c;。。。强烈建议

编译安装Zabbix 2.2 (LNMP环境)

说明&#xff1a;操作系统&#xff1a;CentOS7环境&#xff1a;mysql5.6PHP5.5Nginx1.12Zabbix版本&#xff1a;Zabbix2.2编译安装确实比YUM安装麻烦好多些&#xff0c;但是为了加强对Zabbix的理解&#xff0c;编译安装还是很有意义的&#xff0c;毕竟这样自己能很清楚安装路径…

classlist使用方法_如何通过使用HTML5的classList API在没有jQuery的情况下操作类

classlist使用方法by Ayo Isaiah通过Ayo Isaiah 如何通过使用HTML5的classList API在没有jQuery的情况下操作类 (How to manipulate classes without jQuery by using HTML5s classList API) As a front end developer, you often need to change CSS rules based on how a us…

java面试题收集

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