C#设计模式之二工厂方法模式(Factory Method Pattern)【创建型】
一、引言
在上一篇文章中我们讲解了过渡的一种模式叫做【简单工厂】,也有叫【静态工厂】的,通过对简单工厂模式得了解,我们也发现了它的缺点,就是随着需求的变化我们要不停地修改工厂里面的方法的代码,需求变化越多,里面的If--Else--也越多,这样就会造成简单工厂的实现逻辑过于复杂。设计模式是遵循一定原则而得来的,比如,我们要怎么增加代码,怎么修改代码,不是想怎么来就怎么来的,其中一个原则就是OCP原则,中文是【开放关闭原则】,对增加代码开发,对修改代码关闭,所以我们就不能总是这样修改简单工厂里面的方法。本章介绍的工厂方法模式可以解决简单工厂模式中存在的这个问题,下面就具体看看工厂方法模式是如何解决该问题的。
二、工厂方法模式的胡介绍
2.1、动机(Motivate)
在软件系统的构建过程中,经常面临着“某个对象”的创建工作:由于需求的变化,这个对象(的具体实现)经常面临着剧烈的变化,但是它却拥有比较稳定的接口。
如何应对这种变化?如何提供一种“封装机制”来隔离出“这个易变对象”的变化,从而保持系统中“其他依赖对象的对象”不随着需求改变而改变?
2.2、意图(Intent)
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。 --《设计模式》GoF
2.3、结构图(Structure)

2.4、模式的组成
可以看出,在工厂方法模式的结构图有以下角色:
(1)、抽象工厂角色(Creator): 充当抽象工厂角色,定义工厂类所具有的基本的操作,任何具体工厂都必须继承该抽象类。
(2)、具体工厂角色(ConcreteCreator):充当具体工厂角色,该类必须继承抽象工厂角色,实现抽象工厂定义的方法,用来创建具体产品。
(3)、抽象产品角色(Product):充当抽象产品角色,定义了产品类型所有具有的基本操作,具体产品必须继承该抽象类。
(4)、具体产品角色(ConcreteProduct):充当具体产品角色,实现抽象产品类对定义的抽象方法,由具体工厂类创建,它们之间有一一对应的关系。
2.5、工厂方法模式的代码实现
【简单工厂模式】的问题是:如果有新的需求就需要修改工厂类里面创建产品对象实例的那个方法的实现代码,在面向对象设计一个原则就是哪里有变化,我就封装哪里。还有另外两个大的原则,其一是:面向抽象编程,细节和高层实现都要依赖抽象,第二个原则是:多组合,少继承。这三个原则是最根本的原则,学习设计模式必须以这三个原则为基点,否则都是枉然。根据这三大原则又衍生出来6个具体的原则,分别是【单一职责原则】,【里氏替换原则】,【依赖倒置原则】,【接口隔离原则】、【迪米特法则】和【开闭原则】,既然工厂类有变化,我们就封装它,面向抽象编程,我们先抽象出一个工厂基类,然后,每个需求就实现一个具体的工厂类,这样我们就符合了【开闭原则OCP】,让一个工厂生产一款产品,并一一对应。我们把具体产品的创建推迟到子类中,此时工厂类(这类是基类了)不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式就可以允许系统不修改工厂类逻辑的情况下来添加新产品,这样也就克服了简单工厂模式中缺点。下面就是工厂方法模式的实现代码:
namespace 设计模式之工厂方法模式
{
/// <summary>
/// 汽车抽象类
/// </summary>
public abstract class Car
{
// 开始行驶
public abstract void Go();
} /// <summary>
/// 红旗汽车
/// </summary>
public class HongQiCar : Car
{
public override void Go()
{
Console.WriteLine("红旗汽车开始行驶了!");
}
} /// <summary>
/// 奥迪汽车
/// </summary>
public class AoDiCar : Car
{
public override void Go()
{
Console.WriteLine("奥迪汽车开始行驶了");
}
} /// <summary>
/// 抽象工厂类
/// </summary>
public abstract class Factory
{
// 工厂方法
public abstract Car CreateCar();
} /// <summary>
/// 红旗汽车工厂类
/// </summary>
public class HongQiCarFactory:Factory
{
/// <summary>
/// 负责生产红旗汽车
/// </summary>
/// <returns></returns>
public override Car CreateCar()
{
return new HongQiCar();
}
} /// <summary>
/// 奥迪汽车工厂类
/// </summary>
public class AoDiCarFactory:Factory
{
/// <summary>
/// 负责创建奥迪汽车
/// </summary>
/// <returns></returns>
public override Car CreateCar()
{
return new AoDiCar();
}
} /// <summary>
/// 客户端调用
/// </summary>
class Client
{
static void Main(string[] args)
{
// 初始化创建汽车的两个工厂
Factory hongQiCarFactory = new HongQiCarFactory();
Factory aoDiCarFactory = new AoDiCarFactory(); // 生产一辆红旗汽车
Car hongQi = hongQiCarFactory.CreateCar();
hongQi.Go(); //生产一辆奥迪汽车
Car aoDi = aoDiCarFactory.CreateCar();
aoDi.Go(); Console.Read();
}
}
}
在【工厂方法模式】中,我们同样也把汽车的类抽象出来一个抽象的基类,这里正好符合了【面向抽象编程】,客户端在使用的时候不会依赖具体的什么汽车。使用工厂方法实现的系统,如果系统需要添加新产品时,我们可以利用多态性来完成系统的扩展,对于抽象工厂类和具体工厂中的代码都不需要做任何改动。例如,我们想增加一辆奔驰车,我们只需从Car抽象类下继承一个BenChiCar类,同时在从Factory抽象基类下继承一个“奔驰”的工厂类BenChinaCarFactory就可以了,这样扩展符合OCP的原则。具体代码为:
/// <summary>
/// 奔驰车
/// </summary>
public class BenChiCar : Car
{
/// <summary>
/// 重写抽象类中的方法
/// </summary>
public override void Go()
{
Console.WriteLine("奔驰车开始行驶了!");
}
} /// <summary>
/// 奔驰车的工厂类
/// </summary>
public class BenChiCarFactory : Factory
{
/// <summary>
/// 负责生产奔驰车
/// </summary>
/// <returns></returns>
public override Car CreateCar()
{
return new BenChiCar();
}
} /// <summary>
/// 客户端调用
/// </summary>
class Client
{
static void Main(string[] args)
{ // 如果客户又生产一辆奔驰车
// 再另外初始化一个奔驰车的工厂
Factory benChiCarFactory = new BenChiCarFactory(); // 利用奔驰车的工厂生产奔驰车
Car benChi = benChiCarFactory.CreateCar();
benChi.Go(); Console.Read();
}
}
三、Factory Method模式的几个要点
Factory Method模式主要用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。
Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。
Factory Method模式解决“单个对象”的需求变化;
AbstractFactory模式解决“系列对象”的需求变化;
Builder模式解决“对象部分”的需求变化;
3.1】、工厂方法模式的优点:
(1)、 在工厂方法中,用户只需要知道所要产品的具体工厂,无须关系具体的创建过程,甚至不需要具体产品类的类名。
(2)、在系统增加新的产品时,我们只需要添加一个具体产品类和对应的实现工厂,无需对原工厂进行任何修改,很好地符合了“开闭原则”。
3.2】、工厂方法模式的缺点:
(1)、每次增加一个产品时,都需要增加一个具体类和对象实现工厂,是的系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
3.3】、工厂方法模式使用的场景:
(1)、一个类不知道它所需要的对象的类。在工厂方法模式中,我们不需要具体产品的类名,我们只需要知道创建它的具体工厂即可。
(2)、一个类通过其子类来指定创建那个对象。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
(3)、将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定。
四、.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”文件中找到相关定义,具体定义如下:
<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"/>
配置文件截图了一部分,有时间大家可以自己去研究一下。
下面我们就具体看下工厂方法模式在Asp.net中是如何实现的,如果对一个Index.aspx页面发出请求时,将会调用PageHandlerFactory中GetHandler方法来创建一个Index.aspx对象,它们之间的类图关系如下:

五、总结
每种模式都有自己的使用场合,切记,如果使用错误,还不如不用。工厂方法模式通过面向对象编程中的多态性来将对象的创建延迟到具体工厂中,从而解决了简单工厂模式中存在的问题,也很好地符合了开放封闭原则(即对扩展开发,对修改封闭)。
学习设计模式我们一定要谨记设计模式的几大原则,否则是徒劳无功的。就像学务工一样,我们要记心法。6大原则就像孤独求败的独孤九剑的剑诀,学会了,变化无穷。
C#设计模式之二工厂方法模式(Factory Method Pattern)【创建型】的更多相关文章
- 二十四种设计模式:工厂方法模式(Factory Method Pattern)
工厂方法模式(Factory Method Pattern) 介绍定义一个用于创建对象的接口,让子类决定将哪一个类实例化.Factory Method使一个类的实例化延迟到其子类. 示例有SqlMes ...
- 乐在其中设计模式(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)
一.工厂方法模式的诞生 在读这篇文章之前,我先推荐大家读<设计模式之简单工厂模式(Simple Factory Pattern)>这篇文档.工厂方法模式是针对简单工厂模式中违反开闭原则的不 ...
- IOS设计模式浅析之工厂方法模式(Factory Method)
概述 在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口. 如何隔离出这个易变对象的变化,使得系统中“其它依赖该对象的对 ...
- C#设计模式——工厂方法模式(Factory Method Pattern)
一.概述在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口.如何应对这种变化?如何提供一种封装机制来隔离出“这个易变对象 ...
- 【UE4 设计模式】工厂方法模式 Factory Method Pattern 及自定义创建资源
概述 描述 又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式,或者多态工厂(Polymorphic Factory)模式 工厂父类负责定义创建产品对象的公共接口,而工厂子类 ...
- 工厂方法模式(Factory Method Pattern)
工厂方法模式概述 工厂方法模式是为了弥补简单工厂模式的不足并且继承它的优点而延生出的一种设计模式,属于GoF中的一种.它能更好的符合开闭原则的要求. 定义:定义了一个用于创建对象的接口,但是让子类决定 ...
- 六个创建模式之工厂方法模式(Factory Method Pattern)
问题: 在使用简单工厂模式的时候,如果添加新的产品类,则必需修改工厂类,违反了开闭原则. 定义: 定义一个用于创建对象的接口,让子类决定具体实例化哪个产品类.此时工厂和产品都具有相同的继承结构,抽象产 ...
随机推荐
- python从入门到实践-6章字典
#!/user/bin/env python# -*- coding:utf-8 -*- # 前面不用空格,后面空格# 访问只能通过keyalien_0 = {'color': 'green', 'p ...
- js-day04--Ajax应用--二级联动
Ajax概述和实用需求 Ajax介绍/阿贾克斯:一.Ajax不是一项具体的技术,而是几门技术的综合应用. Javascript.XHTML和CSS.DOM.XML和XMLHttpRequest.二.A ...
- java并发面试
1.在java中守护线程和本地线程区别? java中的线程分为两种:守护线程(Daemon)和用户线程(User). 任何线程都可以设置为守护线程和用户线程,通过方法Thread.setDaemon( ...
- 史上最全java面试题
基本概念 操作系统中 heap 和 stack 的区别 什么是基于注解的切面实现 什么是 对象/关系 映射集成模块 什么是 Java 的反射机制 什么是 ACID BS与CS的联系与区别 Cookie ...
- FFmpeg 学习(四):FFmpeg API 介绍与通用 API 分析
一.FFmpeg 相关术语 1. 容器/文件(Container/File):即特定格式的多媒体文件,比如MP4,flv,mov等. 2. 媒体流(Stream):表示在时间轴上的一段连续的数据,比如 ...
- IntelliJ IDEA 使用 Git 并将 GitHub 作为远程代码仓库
安装本地Git 官方下载地址:http://git-scm.com/downloads 不过这个地址一般下不动,我们可以选择在腾讯软件中心下载,速度很快. 腾讯软件中心的下载地址:https://pc ...
- the python challenge闯关记录(0-8)
0 第零关 2**38 = 274877906944 下一关的url:http://www.pythonchallenge.com/pc/def/274877906944.html 1 第一关 移位计 ...
- 【Storm篇】--Storm中的同步服务DRPC
一.前述 Drpc(分布式远程过程调用)是一种同步服务实现的机制,在Storm中客户端提交数据请求之后,立刻取得计算结果并返回给客户端.同时充分利用Storm的计算能力实现高密度的并行实时计算. 二. ...
- Python内置函数(60)——staticmethod
英文文档: staticmethod(function) Return a static method for function. A static method does not receive a ...
- JVM虚拟机(1)---常用JVM配置参数
常用JVM配置参数 常用JVM配置参数主要有:Trace跟踪参数.堆的分配参数.栈的分配参数. 一.Trace跟踪参数 跟踪参数用于跟踪监控JVM,对于开发人员来讲用于JVM调优以及故障排查的. 1. ...