设计模式(三)工厂方法模式(Factory Pattern)
一、引言
在简单工厂模式中讲到简单工厂模式的缺点,有一点是——简单工厂模式系统难以扩展,一旦添加新产品就不得不修改简单工厂方法,这样就会造成简单工厂的实现逻辑过于复杂,然而本专题介绍的工厂方法模式可以解决简单工厂模式中存在的这个问题,下面就具体看看工厂模式是如何解决该问题的。
二、工厂方法模式的实现
工厂方法模式之所以可以解决简单工厂的模式,是因为它的实现把具体产品的创建推迟到子类中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式就可以允许系统不修改工厂类逻辑的情况下来添加新产品,这样也就克服了简单工厂模式中缺点。
下面看下工厂模式的具体实现代码(这里还是以简单工厂模式中点菜的例子来实现):
namespace 设计模式之工厂方法模式
{
/// <summary>
/// 菜抽象类
/// </summary>
public abstract class Food
{
// 输出点了什么菜
public abstract void Print();
}
/// <summary>
/// 西红柿炒鸡蛋这道菜
/// </summary>
public class TomatoScrambledEggs : Food
{
public override void Print()
{
Console.WriteLine("西红柿炒蛋好了!");
}
}
/// <summary>
/// 土豆肉丝这道菜
/// </summary>
public class ShreddedPorkWithPotatoes : Food
{
public override void Print()
{
Console.WriteLine("土豆肉丝好了");
}
}
/// <summary>
/// 抽象工厂类
/// </summary>
public abstract class Creator
{
// 工厂方法
public abstract Food CreateFoddFactory();
}
/// <summary>
/// 西红柿炒蛋工厂类
/// </summary>
public class TomatoScrambledEggsFactory : Creator
{
/// <summary>
/// 负责创建西红柿炒蛋这道菜
/// </summary>
/// <returns></returns>
public override Food CreateFoddFactory()
{
return new TomatoScrambledEggs();
}
}
/// <summary>
/// 土豆肉丝工厂类
/// </summary>
public class ShreddedPorkWithPotatoesFactory : Creator
{
/// <summary>
/// 负责创建土豆肉丝这道菜
/// </summary>
/// <returns></returns>
public override Food CreateFoddFactory()
{
return new ShreddedPorkWithPotatoes();
}
}
/// <summary>
/// 客户端调用
/// </summary>
class Client
{
static void Main(string[] args)
{
// 初始化做菜的两个工厂()
Creator shreddedPorkWithPotatoesFactory = new ShreddedPorkWithPotatoesFactory();
Creator tomatoScrambledEggsFactory = new TomatoScrambledEggsFactory();
// 开始做西红柿炒蛋
Food tomatoScrambleEggs = tomatoScrambledEggsFactory.CreateFoddFactory();
tomatoScrambleEggs.Print();
//开始做土豆肉丝
Food shreddedPorkWithPotatoes = shreddedPorkWithPotatoesFactory.CreateFoddFactory();
shreddedPorkWithPotatoes.Print();
Console.Read();
}
}
}
使用工厂方法实现的系统,如果系统需要添加新产品时,我们可以利用多态性来完成系统的扩展,对于抽象工厂类和具体工厂中的代码都不需要做任何改动。例如,我们我们还想点一个“肉末茄子”,此时我们只需要定义一个肉末茄子具体工厂类和肉末茄子类就可以。而不用像简单工厂模式中那样去修改工厂类中的实现(具体指添加case语句)。具体代码为:
/// <summary>
/// 肉末茄子这道菜
/// </summary>
public class MincedMeatEggplant : Food
{
/// <summary>
/// 重写抽象类中的方法
/// </summary>
public override void Print()
{
Console.WriteLine("肉末茄子好了");
}
}
/// <summary>
/// 肉末茄子工厂类,负责创建肉末茄子这道菜
/// </summary>
public class MincedMeatEggplantFactory : Creator
{
/// <summary>
/// 负责创建肉末茄子这道菜
/// </summary>
/// <returns></returns>
public override Food CreateFoddFactory()
{
return new MincedMeatEggplant();
}
}
/// <summary>
/// 客户端调用
/// </summary>
class Client
{
static void Main(string[] args)
{ // 如果客户又想点肉末茄子了
// 再另外初始化一个肉末茄子工厂
Creator minceMeatEggplantFactor = new MincedMeatEggplantFactory();
// 利用肉末茄子工厂来创建肉末茄子这道菜
Food minceMeatEggplant = minceMeatEggplantFactor.CreateFoddFactory();
minceMeatEggplant.Print();
Console.Read();
}
}
三、工厂方法模式的UML图
讲解完工厂模式的具体实现之后,让我们看下工厂模式中各类之间的UML图:
从UML图可以看出,在工厂方法模式中,工厂类与具体产品类具有平行的等级结构,它们之间是一一对应的。针对UML图的解释如下:
Creator类:充当抽象工厂角色,任何具体工厂都必须继承该抽象类
TomatoScrambledEggsFactory和ShreddedPorkWithPotatoesFactory类:充当具体工厂角色,用来创建具体产品
Food类:充当抽象产品角色,具体产品的抽象类。任何具体产品都应该继承该类
TomatoScrambledEggs和ShreddedPorkWithPotatoes类:充当具体产品角色,实现抽象产品类对定义的抽象方法,由具体工厂类创建,它们之间有一一对应的关系。
四、.NET中实现了工厂方法的类
.NET 类库中也有很多实现了工厂方法的类,例如Asp.net中,处理程序对象是具体用来处理请求,当我们请求一个*.aspx的文件时,此时会映射到System.Web.UI.PageHandlerFactory类上进行处理,而对*.ashx的请求将映射到System.Web.UI.SimpleHandlerFactory类中(这两个类都是继承于IHttpHandlerFactory接口的),关于这点说明我们可以在“C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\Web.Config”文件中找到相关定义,具体定义如下:
<httpHandlers>
<add path = "*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True" />
<add path = "*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True" />
<add path = "*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True" />
</httpHandlers>
下面我们就具体看下工厂方法模式在Asp.net中是如何实现的,如果对一个Index.aspx页面发出请求时,将会调用PageHandlerFactory中GetHandler方法来创建一个Index.aspx对象,它们之间的类图关系如下:
五、总结
工厂方法模式通过面向对象编程中的多态性来将对象的创建延迟到具体工厂中,从而解决了简单工厂模式中存在的问题,也很好地符合了开放封闭原则(即对扩展开发,对修改封闭)。
以上内容摘抄自:http://learninghard.blog.51cto.com/6146675/1293321
工厂模式好处主要有:
1、将创建实例的工作与使用实例的工作分开;
2、把初始化实例时的工作放到工厂里进行,使代码更容易维护;
3、使得修改代码时不会引起太大的变动,良好的扩展性。
比如,有对象A。现在要修改这个实例的方法。就会有对象B,继承A,然后重写A里面的某个方法。这时,如果没有工厂模式,那么就要把每次创建A对象的代码都改为创建B对象。这是很可怕的一件事情。
如果有工厂模式,那么,我们可以只修改工厂中创建A对象的方法,就可以完成这件事情了。更容易的,可以把这个实例的创建写在配置文件中。那么对于这种变动,只要修改配置文件就可以实现了,不需要修改工厂类。
设计模式(三)工厂方法模式(Factory Pattern)的更多相关文章
- 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern)
原文:乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pa ...
- 【设计模式】工厂方法模式 Factory Method Pattern
在简单工厂模式中产品的创建统一在工厂类的静态工厂方法中创建,体现了面形对象的封装性,客户程序不需要知道产品产生的细节,也体现了面向对象的单一职责原则(SRP),这样在产品很少的情况下使用起来还是很方便 ...
- 设计模式-03工厂方法模式(Factory Method Pattern)
插曲.简单工厂模式(Simple Factory Pattern) 介绍工厂方法模式之前,先来做一个铺垫,了解一下简单工厂模式,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背 ...
- 二十四种设计模式:工厂方法模式(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)模式 工厂父类负责定义创建产品对象的公共接口,而工厂子类 ...
- Java 设计模式(四)-工厂方法模式 (FactoryMethod Pattern)
1 概念定义 1.1 定义 定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类. 1.2 类型 创建类模式 2 原理特征 2.1 类 ...
- Java设计模式之工厂方法模式(转) 实现是抽象工厂?
Java设计模式之工厂方法模式 责任编辑:覃里作者:Java研究组织 2009-02-25 来源:IT168网站 文本Tag: 设计模式 Java [IT168 技术文章] ...
- php设计模式之工厂方法模式
php设计模式之工厂方法模式 工厂方法模式 工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Pol ...
随机推荐
- ABP理论学习之OWIN集成
返回总目录 如果你的应用中使用了OWIN,那么需要在主项目(一般来说是指Web项目)中添加Abp.Owin的nuget包,然后像下面那样在OWIN的 Startup文件中调用 UseAbp()扩展方法 ...
- 从viewport发现小米手机参数不一致
想要在移动web领域有所深造的小伙伴,第一关要过的就是逻辑像素与设备像素之间的关系. 初入移动web,一定要搞懂的几个单位(DPI.PPI.DP.PX 的详细计算方法及算法来源是什么?): dip(d ...
- Hadoop学习笔记—19.Flume框架学习
START:Flume是Cloudera提供的一个高可用的.高可靠的开源分布式海量日志收集系统,日志数据可以经过Flume流向需要存储终端目的地.这里的日志是一个统称,泛指文件.操作记录等许多数据. ...
- 自己动手写游戏:Flappy Bird
START:最近闲来无事,看了看一下<C#开发Flappy Bird游戏>的教程,自己也试着做了一下,实现了一个超级简单版(十分简陋)的Flappy Bird,使用的语言是C#,技术采用了 ...
- Nodejs之MEAN栈开发(一)---- 路由与控制器
因为工作需要,最近再次学习了node,上一次学习node是2014年,纯粹是个人兴趣,学了入门之后没有运用,加上赶别的项目又不了了之.这次正好捡起来.废话不多说,这里的MEAN指的是Mongodb.E ...
- DDD领域驱动设计之领域服务
1.DDD领域驱动设计实践篇之如何提取模型 2.DDD领域驱动设计之聚合.实体.值对象 3.DDD领域驱动设计之领域基础设施层 什么是领域服务,DDD书中是说,有些类或者方法,放实体A也不好,放实体B ...
- ASP.NET Web API中的Controller
虽然通过Visual Studio向导在ASP.NET Web API项目中创建的 Controller类型默认派生与抽象类型ApiController,但是ASP.NET Web API框架本身只要 ...
- Linux查找命令:grep,awk,sed
grep grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具 ...
- Android开发学习之路-二维码学习
这个月装逼有点少了,为什么呢,因为去考软件射鸡师了,快到儿童节了,赶紧写篇博纪念一下逝去的青春,唔,请忽略这句话. 二维码其实有很多种,但是我们常见的微信使用的是一种叫做QRCode的二维码,像下面这 ...
- Rabbitmq安装与配置
install: 1.安装Erlang: $yum -y install erlang 2.安装rabbitmq-server: $rpm --import https://www.rabbitmq. ...