本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7567880.html,记录一下学习过程以备后续查用。

一、引言

接上一篇C#设计模式学习笔记:简单工厂模式(工厂方法模式前奏篇),通过简单工厂模式的了解,它的缺点就是随着需求的变化我们要不停地修改工厂里

面的方法的代码,需求变化越多,里面的if--else也越多,这样就会造成简单工厂的实现逻辑过于复杂。

依设计原则里的开闭原则--对增加代码开放,对修改代码关闭,我们不能总是这样修改简单工厂里面的方法。

下面看看工厂方法模式是如何解决该问题的?

二、工厂方法模式介绍

工厂方法模式:英文名称--Factory Method Pattern;分类--创建型。

2.1、动机(Motivate)

在软件系统的构建过程中,经常面临着“某个对象”的创建工作:由于需求的变化,这个对象(的具体实现)经常面临着剧烈的变化,但是它却拥有比

较稳定的接口。

如何应对这种变化?如何提供一种“封装机制”来隔离出“这个易变对象”的变化,从而保持系统中“其他依赖对象的对象”不随着需求改变而改变?

2.2、意图(Intent)

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。--《设计模式》GoF

2.3、结构图(Structure)

2.4、模式的组成

从上图可以看出,在工厂方法模式的结构图有以下角色:

1)抽象工厂角色(Creator):充当抽象工厂角色,定义工厂类所具有的基本的操作,任何具体工厂都必须继承该抽象类。

2)具体工厂角色(ConcreteCreator):充当具体工厂角色,该类必须继承抽象工厂角色,实现抽象工厂定义的方法,用来创建具体产品。

3)抽象产品角色(Product):充当抽象产品角色,定义了产品类型所有具有的基本操作,具体产品必须继承该抽象类。

4)具体产品角色(ConcreteProduct):充当具体产品角色,实现抽象产品类对定义的抽象方法,由具体工厂类创建,它们之间有一一对应的关系。

2.5、工厂方法模式的具体实现

面向对象设计三大原则:

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
}
}

运行结果如下:

三、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对象,它们之间的类图关系如下:

五、总结

每种模式都有自己的使用场合,切记,如果使用错误,还不如不用。工厂方法模式通过面向对象编程中的多态性来将对象的创建延迟到具体工厂中,

从而解决了简单工厂模式中存在的问题,也很好地符合了开放封闭原则(即对扩展开发,对修改封闭)。

学习设计模式我们一定要谨记设计模式的几大原则,否则是徒劳无功的。就像学务工一样,我们要记心法。几大原则就像独孤九剑的剑诀,学会了,

变化无穷。

C#设计模式学习笔记:(2)工厂方法模式的更多相关文章

  1. Java设计模式学习笔记(三) 工厂方法模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...

  2. Java设计模式(二) 工厂方法模式

    本文介绍了工厂方法模式的概念,优缺点,实现方式,UML类图,并介绍了工厂方法(未)遵循的OOP原则 原创文章.同步自作者个人博客 http://www.jasongj.com/design_patte ...

  3. C#设计模式学习笔记:(5)原型模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7640873.html,记录一下学习过程以备后续查用.  一.引言 很多人说原型设计模式会节省机器内存,他们说 ...

  4. 设计模式(三)工厂方法模式(Factory Pattern)

    一.引言 在简单工厂模式中讲到简单工厂模式的缺点,有一点是——简单工厂模式系统难以扩展,一旦添加新产品就不得不修改简单工厂方法,这样就会造成简单工厂的实现逻辑过于复杂,然而本专题介绍的工厂方法模式可以 ...

  5. 设计模式(2)工厂方法模式(Factory Method)

    设计模式(0)简单工厂模式 设计模式(1)单例模式(Singleton) 源码地址 0 工厂方法模式简介 0.0 工厂方法模式定义 工厂方法模式是在简单工厂模式基础上,为解决更复杂的对象创建问题而衍生 ...

  6. JS学习十七天----工厂方法模式

    工厂方法模式 前言 今天自己看了一下自己写的部分博客,发现写的好丑....開始注意自己的排版!!可是偏亮也不是一朝一夕就完毕的,我尽量让它美丽一点.....每天美丽一点点 正文 工厂方法模式是一种实现 ...

  7. java23种设计模式(一)工厂方法模式

    在说工厂方法模式之前,先了解一下简单工厂模式.工厂方法模式其实是在简单工厂上面做了一些增强. 简单工厂模式:有一个专门的类来生产其他类的实例,生产的这些实例有一个共同父类.这个跟我们的多态有一点像. ...

  8. Java设计模式(四)工厂方法模式

    定义与类型 定义:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行. 类型:创建型 适用场景 创建对象需要大量重复的代码 客户端(应用层)不依赖于产 ...

  9. 【python设计模式-创建型】工厂方法模式

    工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻 ...

  10. 设计模式C#合集--工厂方法模式

    简单工厂,代码: public interface ISpeak { public void Say(); } public class Hello : ISpeak { public void Sa ...

随机推荐

  1. ROS和Gazebo进行机器人仿真(二)

    一.在Gazebo中使用ROS控制器 在本节中,我们将讨论如何在Gazebo中让机器人的每个关节运动. 为了让关节动起来,我们需要分配一个ROS控制器,尤其是,我们需要为每个关节连上一个与transm ...

  2. django 发布会签到系统web开发

    引言 最近学习了虫师的发布会签到系统demo,结合自己所学django知识,对demo重新塑造了一下.也是为了练练手,巩固知识.现在就分享一下成果~ Django工作流 学习django web开发, ...

  3. android webview正确显示音标

    package com.example.fonttest; import android.support.v7.app.ActionBarActivity; import android.webkit ...

  4. 谈恋爱就像TCP连接

    这是一张很内涵的漫画--爱情是靠不住的,即使你使用TCP连接也是如此.一心要握手成功,却被RST的男人就是个彻底的杯具-- 小知识: 一个虚拟连接的建立是通过三次握手来实现的. 第一次握手:建立连接时 ...

  5. Visual Studio 2012 出现关于ActivityLog.xml错误的解决方案

    由sp1升级sp2后出现的错误. devenv.exe /safemode启动下,就可以了 命令列參數 描述 /Command (devenv.exe) 啟動 IDE 並執行指定的命令. /Debug ...

  6. nginx+lua在我司的实践

    导读:nginx是一个高性能的反向代理服务器,lua是一个小巧的脚本语言,这两个的巧妙结合会擦出怎样的火花呢. 关键词:nginx,lua,nginx+lua 前言 nginx,lua,nginx+l ...

  7. TensorFlow中使用GPU

    TensorFlow默认会占用设备上所有的GPU以及每个GPU的所有显存:如果指定了某块GPU,也会默认一次性占用该GPU的所有显存.可以通过以下方式解决: 1 Python代码中设置环境变量,指定G ...

  8. BZOJ 2653 middle (可持久化线段树+中位数+线段树维护最大子序和)

    题意: 左端点在[a,b],右端点在[c,d],求这个线段里中位数(上取整)最大值 思路: 对数组离散化,对每一个值建中位数的可持久化线段树(有重复也没事),就是对于root[i],大于等于i的值为1 ...

  9. Android Studio 学习笔记(二):布局简介和xmlns说明

    初学Android Studio,是在b站看的教程视频,这里的笔记也是以其为基础的,个人强烈安利: [天哥]Android开发视频教程最新版 Android Studio开发 Android 布局简介 ...

  10. How to setup backup by using EMC NW + EMC NMM for sqlserver failover cluster (not always on)

    As we said, sqlsever fail over cluster is perviously version of always on. The HA was guarenteed by ...