本笔记摘抄自:http://www.javashuo.com/article/p-gfqxtqtz-hg.html,记录一下学习过程以备后续查用。html
1、引言编程
接上一篇C#设计模式学习笔记:简单工厂模式(工厂方法模式前奏篇),经过简单工厂模式的了解,它的缺点就是随着需求的变化咱们要不停地修改工厂里设计模式
面的方法的代码,需求变化越多,里面的if--else也越多,这样就会形成简单工厂的实现逻辑过于复杂。ide
依设计原则里的开闭原则--对增长代码开放,对修改代码关闭,咱们不能老是这样修改简单工厂里面的方法。post
下面看看工厂方法模式是如何解决该问题的?学习
2、工厂方法模式介绍ui
工厂方法模式:英文名称--Factory Method Pattern;分类--建立型。atom
2.一、动机(Motivate)url
在软件系统的构建过程当中,常常面临着“某个对象”的建立工做:因为需求的变化,这个对象(的具体实现)常常面临着剧烈的变化,可是它却拥有比spa
较稳定的接口。
如何应对这种变化?如何提供一种“封装机制”来隔离出“这个易变对象”的变化,从而保持系统中“其余依赖对象的对象”不随着需求改变而改变?
2.二、意图(Intent)
定义一个用于建立对象的接口,让子类决定实例化哪个类。Factory Method使得一个类的实例化延迟到子类。--《设计模式》GoF
2.三、结构图(Structure)
2.四、模式的组成
从上图能够看出,在工厂方法模式的结构图有如下角色:
1)抽象工厂角色(Creator):充当抽象工厂角色,定义工厂类所具备的基本的操做,任何具体工厂都必须继承该抽象类。
2)具体工厂角色(ConcreteCreator):充当具体工厂角色,该类必须继承抽象工厂角色,实现抽象工厂定义的方法,用来建立具体产品。
3)抽象产品角色(Product):充当抽象产品角色,定义了产品类型全部具备的基本操做,具体产品必须继承该抽象类。
4)具体产品角色(ConcreteProduct):充当具体产品角色,实现抽象产品类对定义的抽象方法,由具体工厂类建立,它们之间有一一对应的关系。
2.五、工厂方法模式代码实现
面向对象设计三大原则:
1)哪里有变化就封装哪里。
2)面向抽象编程,细节和高层实现都要依赖抽象。
3)多组合,少继承。
这三大原则是最根本的原则,学习设计模式必须以这三个原则为基点,不然都是枉然。根据这三大原则又衍生出来6个具体的原则,分别是单一职责
原则、开闭原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特法则。
既然工厂类有变化,咱们就封装它,面向抽象编程。咱们先抽象出一个工厂基类,而后每一个需求都实现一个具体的工厂类,这样咱们就符合了开闭原
则,让一个工厂生产一款产品,并一一对应。具体产品的建立推迟到子类中,此时工厂类(基类)再也不负责全部产品的建立,而只是给出具体工厂必须
实现的接口,这样工厂方法模式就能够容许系统不修改工厂类逻辑的状况下来添加新产品,也就克服了简单工厂模式中缺点。
下面是工厂方法模式的实现代码:
class Program { /// <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(); } } static void Main(string[] args) { #region 工厂方法模式 //初始化建立汽车的两个工厂 Factory hongQiCarFactory = new HongQiCarFactory(); Factory aoDiCarFactory = new AoDiCarFactory(); //生产一辆红旗汽车 Car hongQi = hongQiCarFactory.CreateCar(); hongQi.Go(); //生产一辆奥迪汽车 Car aoDi = aoDiCarFactory.CreateCar(); aoDi.Go(); Console.Read(); #endregion } }
运行结果以下:
使用工厂方法实现的系统,若是系统须要添加新产品时,咱们能够利用多态性来完成系统的扩展,对于抽象工厂类和具体工厂中的代码都不须要作任
何改动。假如咱们想生产奔驰车,咱们只需从Car抽象类下继承一个BenChiCar类、在Factory抽象类下继承一个“奔驰”的工厂类BenChiCarFactory就可
以实现了:
class Program { /// <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 class BenChiCar : 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> public class BenChiCarFactory : Factory { /// <summary> /// 负责生产奔驰汽车 /// </summary> /// <returns></returns> public override Car CreateCar() { return new BenChiCar(); } } static void Main(string[] args) { #region 工厂方法模式 //初始化建立汽车的两个工厂 Factory hongQiCarFactory = new HongQiCarFactory(); Factory aoDiCarFactory = new AoDiCarFactory(); Factory benChiCarFactory = new BenChiCarFactory(); //生产一辆红旗汽车 Car hongQi = hongQiCarFactory.CreateCar(); hongQi.Go(); //生产一辆奥迪汽车 Car aoDi = aoDiCarFactory.CreateCar(); aoDi.Go(); //生产一辆奔驰汽车 Car benChi = benChiCarFactory.CreateCar(); benChi.Go(); Console.Read(); #endregion } }
运行结果以下:
3、Factory Method模式的几个要点
Factory Method模式主要用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个常常变化的具体类型,紧耦合关系会致使软件的脆弱;
Factory Method模式经过面向对象的手法,将所要建立的具体对象工做延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦
合关系;
Factory Method模式解决“单个对象”的需求变化;
AbstractFactory模式解决“系列对象”的需求变化;
Builder模式解决“对象部分”的需求变化;
3.一、工厂方法模式的优势
1)在工厂方法中,用户只须要知道所要产品的具体工厂,无须关心具体的建立过程,甚至不须要具体产品类的类名。
2)在系统增长新的产品时,咱们只须要添加一个具体产品类和对应的实现工厂,无需对原工厂进行任何修改,很好地符合了“开闭原则”。
3.2工厂方法模式的缺点
1)每次增长一个产品时,都须要增长一个具体类和对象实现工厂,使得系统中类的个数成倍增长,在必定程度上增长了系统的复杂度,同时也增长
了系统具体类的依赖,这并非什么好事。
3.3工厂方法模式的使用场合
1)一个类不知道它所须要的对象的类。在工厂方法模式中,咱们不须要具体产品的类名,咱们只须要知道建立它的具体工厂便可。
2)一个类经过其子类来指定建立那个对象。在工厂方法模式中,对于抽象工厂类只须要提供一个建立产品的接口,由其子类来肯定具体要建立的对
象。在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
3)将建立对象的任务委托给多个工厂子类中的某一个,客户端在使用时能够无须关心是哪个工厂子类建立产品子类,须要时再动态指定。
4、.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对象,它们之间的类图关系以下:
5、总结
每种模式都有本身的使用场合,切记,若是使用错误,还不如不用。工厂方法模式经过面向对象编程中的多态性来将对象的建立延迟到具体工厂中,
从而解决了简单工厂模式中存在的问题,也很好地符合了开放封闭原则(即对扩展开发,对修改封闭)。
学习设计模式咱们必定要谨记设计模式的几大原则,不然是徒劳无功的。就像学务工同样,咱们要记心法。几大原则就像独孤九剑的剑诀,学会了,
变化多端。