当前位置: 首页 > news >正文

设计模式(三)工厂方法模式(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页面发出请求时,将会调用PageHandlerFactoryGetHandler方法来创建一个Index.aspx对象,它们之间的类图关系如下:

五、总结


工厂方法模式通过面向对象编程中的多态性来将对象的创建延迟到具体工厂中,从而解决了简单工厂模式中存在的问题,也很好地符合了开放封闭原则(即对扩展开发,对修改封闭)。

 

以上内容摘抄自:http://learninghard.blog.51cto.com/6146675/1293321

 

工厂模式好处主要有:
1、将创建实例的工作与使用实例的工作分开;
2、把初始化实例时的工作放到工厂里进行,使代码更容易维护;
3、使得修改代码时不会引起太大的变动,良好的扩展性。
比如,有对象A。现在要修改这个实例的方法。就会有对象B,继承A,然后重写A里面的某个方法。这时,如果没有工厂模式,那么就要把每次创建A对象的代码都改为创建B对象。这是很可怕的一件事情。
如果有工厂模式,那么,我们可以只修改工厂中创建A对象的方法,就可以完成这件事情了。更容易的,可以把这个实例的创建写在配置文件中。那么对于这种变动,只要修改配置文件就可以实现了,不需要修改工厂类。

转载于:https://www.cnblogs.com/xiongzaiqiren/p/5280299.html

相关文章:

  • jQuery 增加 删除 修改select option
  • LINQ查收数据库的性能瓶颈
  • Stream groupings
  • 重构第4天:降低方法(Push Down Method)
  • [基础] 重载的时候什么时候用引用
  • 技术架构的关注点
  • 在线生成GIF文件
  • 给厕所换了一个排污管
  • CocoaPods简单配置。
  • Java8:使用Lambda表达式增强版Comparator排序
  • Java注解
  • Linux内核分析5
  • C#基础知识点
  • 不用bootstrap,只用CSS创建网格布局
  • 次小生成树模板
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • angular2 简述
  • C# 免费离线人脸识别 2.0 Demo
  • Docker容器管理
  • dva中组件的懒加载
  • IP路由与转发
  • Javascript基础之Array数组API
  • MaxCompute访问TableStore(OTS) 数据
  • PAT A1092
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • vue自定义指令实现v-tap插件
  • 包装类对象
  • 关于Java中分层中遇到的一些问题
  • 经典排序算法及其 Java 实现
  • 聚类分析——Kmeans
  • 如何合理的规划jvm性能调优
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 说说动画卡顿的解决方案
  • 运行时添加log4j2的appender
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • #Linux(make工具和makefile文件以及makefile语法)
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (ZT)一个美国文科博士的YardLife
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .Net Core webapi RestFul 统一接口数据返回格式
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .net mvc 获取url中controller和action
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .net 提取注释生成API文档 帮助文档
  • .net下简单快捷的数值高低位切换
  • /proc/stat文件详解(翻译)
  • @Controller和@RestController的区别?
  • @FeignClient 调用另一个服务的test环境,实际上却调用了另一个环境testone的接口,这其中牵扯到k8s容器外容器内的问题,注册到eureka上的是容器外的旧版本...
  • [Angular 基础] - 表单:响应式表单