设计模式(2)工厂方法模式(Factory Method)
0 工厂方法模式简介
0.0 工厂方法模式定义
工厂方法模式是在简单工厂模式基础上,为解决更复杂的对象创建问题而衍生进化出来的一种创建型模式。
工厂方法模式的核心思想是定义一个用于创建对象的接口,让其子类去决定去实例化哪个具体类的对象,工厂方法模式可以使一个类的实例化动作延迟到其子类。
工厂方法模式结构图如下
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();
}
4、通过反射实例化具体的工厂方法类
在实际应用中跟上面不同种族创建英雄的例子类似,一般在系统启动时就已经确定要使用哪种方法实例化工厂方法类,通常我们可以将工厂类的实例化通过配置文件的方式确定,从而避免源码的修改。
string factoryName = ConfigurationManager.AppSettings["FactoryName"]; // 读取配置文件
IFactory factory = (IFactory)Assembly.Load("FactoryMethodPattern").CreateInstance("FactoryMethodPattern." + factoryName); // 实例化配置的工厂方法类
2 总结
工厂方法模式具有以下优点
1、更容易对现有功能进行扩展,如果有新的需求,只需要实现一个相应的工厂方法实现类即可,无需修改现有代码。
2、不同工厂方法类,实现了单一职责的设计原则。
工厂方法模式的缺点
由于具体的对象由具体指定的工厂方法类创建,导致具体产品和工厂方法类之间具有较强的耦合性
设计模式(2)工厂方法模式(Factory Method)的更多相关文章
- 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern)
原文:乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pa ...
- 设计模式-03工厂方法模式(Factory Method Pattern)
插曲.简单工厂模式(Simple Factory Pattern) 介绍工厂方法模式之前,先来做一个铺垫,了解一下简单工厂模式,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背 ...
- 【设计模式】工厂方法模式 Factory Method Pattern
在简单工厂模式中产品的创建统一在工厂类的静态工厂方法中创建,体现了面形对象的封装性,客户程序不需要知道产品产生的细节,也体现了面向对象的单一职责原则(SRP),这样在产品很少的情况下使用起来还是很方便 ...
- 二十四种设计模式:工厂方法模式(Factory Method Pattern)
工厂方法模式(Factory Method Pattern) 介绍定义一个用于创建对象的接口,让子类决定将哪一个类实例化.Factory Method使一个类的实例化延迟到其子类. 示例有SqlMes ...
- 设计模式之工厂方法模式(Factory Method Pattern)
一.工厂方法模式的诞生 在读这篇文章之前,我先推荐大家读<设计模式之简单工厂模式(Simple Factory Pattern)>这篇文档.工厂方法模式是针对简单工厂模式中违反开闭原则的不 ...
- 设计模式之 - 工厂方法模式 (Factory Method design pattern)
1. 模式意图: 定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类. 2. 别名(Virtual Constructor) 3. 结构 4. 工厂方法模式C ...
- 【UE4 设计模式】工厂方法模式 Factory Method Pattern 及自定义创建资源
概述 描述 又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式,或者多态工厂(Polymorphic Factory)模式 工厂父类负责定义创建产品对象的公共接口,而工厂子类 ...
- 工厂方法模式-Factory Method(Java实现)
工厂方法模式-Factory Method 工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法让实例化的具体内容交给子类工厂来进行. 本文中的例子是这样的. 生产一个身份证, ...
- 浅谈C++设计模式之工厂方法(Factory Method)
为什么要用设计模式?根本原因是为了代码复用,增加可维护性. 面向对象设计坚持的原则:开闭原则(Open Closed Principle,OCP).里氏代换原则(Liskov Substitution ...
- IOS设计模式浅析之工厂方法模式(Factory Method)
概述 在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口. 如何隔离出这个易变对象的变化,使得系统中“其它依赖该对象的对 ...
随机推荐
- 微坑---微信小程序ios上时间字符串转换为时间戳时,在开发工具上和安卓手机上运行成功
给定一个时间字符串 var time="2017-02-27 16:42:53" js有三种转换为时间戳的方法:1.var timestamp = Date.parse(time ...
- Win10或Win8下ObjectARX2015 Wizard向导创建项目失败解决方法
[原创]objectARX 2015 Wizard安装向导在Win8/win10下无法创建项目的解决方法总结by edata @2017-5-1objectARX 2015 Wizard安装向导在Wi ...
- redis持久化快速回忆手册
Redis提供的持久化机制: 1). RDB持久化:该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘. 2). AOF持久化:该机制将以日志的形式记录服务器所处理的每一个写操作,在Redis服 ...
- mysql主从复制-异步复制
一.创建复制账号: 在Master的数据库中建立一个备份帐户:每个Slave使用标准的MySQL用户名和密码连接master. 进行复制操作的用户会授予REPLICATION SL ...
- c#枚举值增加特性说明
c#枚举值增加特性说明 通过特性给一个枚举类型每个值增加一个字符串说明,用于打印或显示. 自定义打印特性 [AttributeUsage(AttributeTargets.Field)] public ...
- 用 Entity Framework结合Oracle数据库来开发项目
项目需要,要使用Oracle 11g数据库.作为不想写SQL的程序员,所以...... 原先想当然的是使用EF+MSSQL的方式来进行配置.吃了哑巴亏.然后谷歌出了一篇好文,沿着这篇文章进行了搭建,I ...
- JS中this到底指向谁?
关于this的指向,是一个令人很头疼的问题.但是,你运气好,碰到了我.老夫这儿有本祖传秘籍,看懂这个,妈妈再也不用担心你的this指向不对啦! 归根结底,this指向就一句话:谁最终调用函数,this ...
- MySQL 闪回工具之 binlog2sql
生产上误删数据.误改数据的现象也是时常发生的现象,作为 DBA 这时候就需要出来补锅了,最开始的做法是恢复备份,然后从中找到需要的数据再进行修复,但是这个时间太长了,对于大表少数数据的修复来讲,动作太 ...
- 将非官方扩展程序加入chrome的白名单
参考来源:http://xclient.info/a/1ddd2a3a-d34b-b568-c0d0-c31a95f0b309.html com.google.Chrome.mobileconfig ...
- iOS安全攻防之结构体保护使用
Objective-C 代码很容易被 hook,因此需要对一些重要的业务逻辑进行保护,可以改用结构体的形式,把函数名隐藏在结构体里,以函数指针成员的形式存储.这样编译后只留了下地址,去掉了名字和参数表 ...