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)
问题: 在使用简单工厂模式的时候,如果添加新的产品类,则必需修改工厂类,违反了开闭原则. 定义: 定义一个用于创建对象的接口,让子类决定具体实例化哪个产品类.此时工厂和产品都具有相同的继承结构,抽象产 ...
随机推荐
- java枚举使用 总结
补充几点: 1.枚举对象是可以用 == 比较. 2. TestEnum3反编译结果: F:\tree\Test\src\test>javap TestEnum3* Compiled from & ...
- For each...in / For...in / For...of 的解释与例子
1.For each...in for each...in 语句在对象属性的所有值上迭代指定的变量.对于每个不同的属性,执行一个指定的语句. 语法: for each (variable in obj ...
- Java提高篇(三):内部类和匿名内部类
一,内部类 其实内部类是十分简单的,我们根据其字里行间的意义就可以知道内部类应该是一个类当中的一个类,相当于一个类进行了嵌套,就如同循环的嵌套一般. 内部类有一个特征:内部类当中可以调用外部类当中的属 ...
- 精选 TOP45 值得学习的Python项目
精选 TOP45 值得学习的Python项目 [导读]热门资源博客 Mybridge AI 比较了 18000 个关于 Python 的项目,并从中精选出 45 个最具竞争力的项目.我们进行了翻译,在 ...
- toastr操作完成提示框
toastr.js组件 关于信息提示框,项目中使用的是toastr.js这个组件,这个组件最大的好处就是异步.无阻塞,提示后可设置消失时间,并且可以将消息提示放到界面的各个地方. 官方文档以及源码 源 ...
- [Swift]LeetCode668. 乘法表中第k小的数 | Kth Smallest Number in Multiplication Table
Nearly every one have used the Multiplication Table. But could you find out the k-th smallest number ...
- jquery配合.NET实现点击指定绑定数据并且能够一键下载
最近在做培训管理系统中遇到一个问题,需求需点击绑定的数据,将指定的附件下载下来,并且是批量下载(绑定的数据非datagrid,后台拼接的绑定). 效果图如下: 大体思路: 1.jquery得到选中的绑 ...
- Ceres配置(vs2013+Win10)
主要参考文:Ceres Solver 在Windows下安装配置笔记 eigen.gflags.glog.suitesparse按照上面的链接中的指导配置即可. 配置ceres的时候,按照上面的链接内 ...
- IntelliJ IDEA 自定义方法注解模板
最近没啥事开始正式用Eclipse 转入 idea工具阵营,毕竟有70%的开发者在使用idea开发,所以它的魅力可想而知.刚上手大概有一天,就知道它为啥取名为 intelli(智能化)了,确实很智能, ...
- python3+ selenium3开发环境搭建-手把手教你安装python(详细)
环境搭建 基于python3和selenium3做自动化测试,俗话说:工欲善其事必先利其器:没有金刚钻就不揽那瓷器活,磨刀不误砍柴工,因此你必须会搭建基本的开发环境,掌握python基本的语法和一个I ...