Simple Factory Pattern (简单工厂模式)

特性:

  • 把类的实例化工作,集中到一个「工厂类」去处理,亦即将 new instance 的工作,都交给一个「工厂」去处理,而不要分散写在各个类中。
  • 客户端程序,与创建实例 (对象) 的工作必须隔离,亦即「解耦」,客户端程序只要专注于自己的业务逻辑。适用于客户端程序在开发过程中,尚无法预知要创建的具体类型。
  • 产品具体的实现能和客户端隔离,便于事后抽换。

Simple Factory Pattern (简单工厂模式)、Factory Method Pattern (工厂方法模式),在实作的代码中,有时很难明确去界定此二者。Simple Factory 的特性,如前所述,在于将创建实例 (new instance) 的工作,集中由特定的一个「工厂类」来处理,避免写在各个类中,以方便日后添加新功能,和修改既有的功能。

如下「进口水果」的代码,为 O'Reilly 的「C# 3.0 Design Patterns」这本书籍 [1] 第五章的 Factory Method 示例。乍看之下,我觉得它比较像 Simple Factory Pattern,因其仍将创建实例,和部分逻辑判断的工作,都集中在一个 工厂类 (Creator1 类) 去处理,导致日后要添加新功能 (多引进一个国家的水果),或要修改判断「进口月份」的逻辑时,仍要修改 server-side 的这个「工厂类」,而无法只修改 client-side 的 Page_Load 方法,违背了「开放-封闭」原则。

但这个示例,要实例化哪个类型,是由「工厂类」以及客户端 (水果店主人) 的 Page_Load 方法,共同决定的。透过 IProduct 接口,看似隔离了客户端程序、具体 Product 的依赖关系,但客户端程序仍有创建对象的决定权,因此其与创建实例 (对象) 的工作并未真正隔离。

SimpleFactory.aspx.cs
using System;

//这个示例事实上算是一个 Factory Method Pattern
public partial class SimpleFactory : System.Web.UI.Page
{
    //客户端调用(Client-Side)。这个示例的客户端,如同一间水果店的店主人。
    protected void Page_Load(object sender, EventArgs e)
    {
        Creator1 c = new Creator1();    //工厂类實體
        IProduct product;

//由客户端决定要具体实例化哪些类型。
        //但此示例的特点,为客户端不需要知道产品类型。
        for (int i = 1; i <= 12; i++)
        {
            //客户端不需要知道产品类型。把创建哪种具体产品的决定,委托给了工厂方法
            product = c.factoryMethod(i);
            Response.Write("水果进口, " + i + "月: " + product.shipFrom() + "
");
        }
    }

//这个示例,要实例化哪个类型,是由「工厂类」以及 Client-Side 的 Page_Load() 方法,共同决定的。
    //透过 IProduct 接口,看似隔离了客户端程序、具体 Product 的依赖关系,
    //但客户端程序仍有创建对象的决定权,因此其与创建实体 (对象) 的工作并未真正隔离。
    
    //即使日后修改了某个子类 shipFrom() 里的实作方式,对客户端不会有影响,
    //客户端只要知道如何操作 shipFrom() 去进口水果即可。
}

//所有的产品,必须实现这个接口。如此一来,先建立一种「契约」,
//以后要增添、修改产品时,就可由这个接口(或抽象类)来操作。
interface IProduct
{
    //隐藏实现细节。
    //事前不知道要创建哪种类的实体(产品),延至 Creator1 类或「客户端」中实现。
    string shipFrom();
}

//单一职责原则,每一个类都只负责一件具体的事情。
// 台湾的水果供货商。
class ProductA : IProduct
{
    public string shipFrom()
    {
        return " from 台湾";
    }
}

//单一职责原则,每一个类都只负责一件具体的事情。
// 美国的水果供货商。
class ProductB : IProduct
{
    public string shipFrom()
    {
        return "from 美国";
    }
}

//单一职责原则,每一个类都只负责一件具体的事情
class DefaultProduct : IProduct
{
    public string shipFrom()
    {
        return "不进口";
    }
}

//工厂类 (水果采购人员),负责创建实体(采购水果)。只有这个类,知道如何创建这些产品的逻辑
class Creator1
{
    //日后若引进新产品 (多引进一个国家的水果)、修改旧产品,可集中在这里抽换;
    //但缺点亦如是,亦即仍需修改这里的 Server-Side 代码,必须修改此一工厂类。

//此处做法,偏向「简单工厂模式」的实体创建。
    public IProduct factoryMethod(int month)
    {
        if (month >= 4 && month <= 11)
            return new ProductA();
        else
            if (month == 1 || month == 2 || month == 12)
                return new ProductB();
            else
                return new DefaultProduct();
    }
}

//另一个工厂类
//class Creator2
//{
//    public IProduct factoryMethod(int month, int day)
//    {
//        不同的水果进口方式
//    }
//}

/* 
执行结果:

水果进口, 1月: from 美国
水果进口, 2月: from 美国
水果进口, 3月: 不进口
水果进口, 4月: from 台湾
水果进口, 5月: from 台湾
水果进口, 6月: from 台湾
水果进口, 7月: from 台湾
水果进口, 8月: from 台湾
水果进口, 9月: from 台湾
水果进口, 10月: from 台湾
水果进口, 11月: from 台湾
水果进口, 12月: from 美国

*/
//


图 1 Sybase PowerDesigner 绘制的「进口水果」示例的 Class Diagram

--------------------------------------------------------

Factory Method Pattern (工厂方法模式)

特性:

  • 由子类来决定要具体实例化哪种类型。这些子类实现了某个共通的接口,或继承自某个共用的抽象类。
  • 让一个类的实例化,延迟到其子类。
  • 由客户端程序,来决定要创建哪些工厂类型。

上述特性的第一点,所提到的子类,如同下方示例里的「博派Factory」类、「狂派Factory」类。

上述特性的第三点,Factory Method 和 Simple Factory 刚好相反。Factory Method 把 Simple Factory 中「工厂类」的逻辑判断,移到客户端来进行。日后若想添加、修改功能,原本 Simple Factory 是要修改「工厂类」的,但 Factory Method 变成要修改客户端程序,但也改善了 Simple Factory 的缺点,亦即不用再冒险修改原本已可正常工作的 server-side「工厂类」,而只要改 client-side 的 Page_Load 方法,符合了「开放-封闭」原则。

Factory Method 的实现方式有很多种,但原则为,先用一个抽象类或接口,当作定义 (如下方示例的 IFactory),并留下抽象方法而不实作 (如下方示例的 createTransformer 方法)。要延迟到子类,由子类来决定要实例化哪种类型 (如下方示例的「博派Factory」和「狂派Factory」这两个子类)。

FactoryMethod.aspx.cs
using System;

public partial class FactoryMethod : System.Web.UI.Page
{
    //客户端调用(Client-Side)。
    protected void Page_Load(object sender, EventArgs e)
    {
        //客户端程序调用的时候,只要改右侧创建实体的类型即可
        IFactory factory1 = new 博派Factory();
        变形金刚 擎天柱 = factory1.createTransformer();
        擎天柱.transformCar();

//把职责委托给平行层次中的子类
        IFactory factory2 = new 狂派Factory();
        变形金刚 威震天 = factory2.createTransformer();
        威震天.transformAirplane();
    }
}

//IProduct
class 变形金刚
{
    public virtual void transformCar()
    {
        Console.WriteLine("变汽车");
    }

public virtual void transformAirplane()
    {
        Console.WriteLine("变飞机");
    }

public virtual void transformAnimal()
    {
        Console.WriteLine("变动物");
    }
}

//IProduct 的子类
class 博派 : 变形金刚
{ }

//IProduct 的子类
class 狂派 : 变形金刚
{ }

//变形金刚工厂 (亦可用抽象类)
interface IFactory
{
    //隐藏实现细节。
    //事前不知道要创建哪种变形金刚,延至「客户端」中实现。
    变形金刚 createTransformer();
}

//博派的工厂 (由此种子类来决定具体实例化哪种类型)
class 博派Factory : IFactory
{
    public 变形金刚 createTransformer()
    {
        return new 博派();
    }
}

//狂派的工厂 (由此种子类来决定具体实例化哪种类型)
class 狂派Factory : IFactory
{
    public 变形金刚 createTransformer()
    {
        return new 狂派();
    }
}

//以后引进新产品 (堕落金刚) 时,我们不需要冒险修改既有的「工厂类」,而只要添加新的产品类、新的工厂类,
//最后由 IFactory 的子类,以及客户端程序 (Page_Load 方法),来决定要创建哪些具体类型;
//整个架构变成只有「扩展」的变化,而不再有「修改」的变化。

//若要修改旧功能,如狂派类,要加入组合成「大力神」的功能时,也只需要修改既有的「狂派」类。


图 2 Sybase PowerDesigner 绘制的「变形金刚 - 工厂方法模式」Class Diagram

以后引进新产品 (堕落金刚) 时,我们不需要冒险修改既有的「工厂类」,而只要添加新的「产品类」、新的「工厂类」,最后由 IFactory 的子类,以及客户端程序 (Page_Load 方法),来决定要创建哪些具体类型;整个架构变成只有「扩展」的变化,而不再有「修改」的变化。此外,若要修改旧功能,如:「狂派」类,要加入组合成「大力神」的功能时,也只需要修改既有的「狂派」类即可。

Factory Method Pattern 并无固定的实现方式,上述两个示例,仅为其中一种实现方式,若参考一些 Java 的论坛、书籍、文件,还能找到更多的变化应用 [7], [8]。

艾伟:C# Design Patterns (1) - Factory Method相关推荐

  1. 艾伟_转载:C# Design Patterns (4) - Proxy

    本帖介绍 Proxy Pattern (代理模式). Proxy Pattern (代理模式) The Proxy Pattern provides a surrogate or placeholde ...

  2. Design Pattern - Factory Method(C#)

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! Defi ...

  3. 艾伟_转载:C# Design Patterns (3) - Decorator

    Decorator Pattern (装饰模式) 装饰模式可「动态」地给一个对象添加一些额外的职责,提供有别于「继承」的另一种选择.就扩展功能而言,Decorator Pattern 透过 Aggre ...

  4. 艾伟_转载:.NET设计模式:工厂方法模式(Factory Method)

    概述 在软件系统中,经常面临着"某个对象"的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口.如何应对这种变化?提供一种封装机制来隔离出 ...

  5. 在 Java 中应用设计模式 - Factory Method

    基本概念 FactoryMethod是一种创建性模式,它定义了一个创建对象的接口,但是却让子类来决定具体实例化哪一个类.当一个类无法预料要创建哪种类的对象或是一个类需要由子类来指定创建的对象时我们就需 ...

  6. 设计模式(Design Patterns)详解

    设计模式(Design Patterns) --可复用面向对象软件的基础一般会用到的: Factory( 工厂模式) Singleton(单例模式) 这两个比较多 Proxy(代理模式) Adapte ...

  7. 设计模式-Factory Method Pattern

    为什么80%的码农都做不了架构师?>>>    一. 工厂方法(Factory Method)模式 工厂方法(FactoryMethod)模式是类的创建模式,其用意是定义一个创建产品 ...

  8. Java23中设计模式(Design Patterns)详解

    2019独角兽企业重金招聘Python工程师标准>>> 设计模式(Design Patterns) --可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复 ...

  9. 设计模式教程(Design Patterns Tutorial)笔记之一 创建型模式(Creational Patterns)...

    设计模式教程(Design Patterns Tutorial)笔记之一 创建型模式(Creational Patterns) 目录 · 概述 · Factory · What is the Fact ...

最新文章

  1. yolov3模型识别不出训练图片_YOLOv3训练自己的模型
  2. Linux Centos7安装chrome浏览器
  3. Eclipse的SVN插件移动中文名称文件提示org.tigris.subversion.javahl.ClientException: Bogus URL...
  4. cuda 编 程(六)简单CUDA程序的基本框架
  5. 项目中要使用到动态规划该怎么应用,怎么说?
  6. GCD dispatch_semaphore
  7. 【空间数据库】Windows操作系统PostgreSQL+PostGIS环境搭建图文安装教程
  8. 谷歌修复安卓蓝牙组件中无需用户交互的 bug
  9. [转载] python __import__ 搜索路径详解
  10. docunment对象
  11. python3-基础8
  12. bzoj 3208 花神的秒题计划I
  13. React-注册事件
  14. linux profile文件,全面解析Linux profile文件
  15. 自己动手开发编译器(三)有穷自动机
  16. 华为CANN训练营笔记——应用开发全流程 [5](with 代码版)
  17. linux 快速建文件目录,在Linux中批量创建和修改文件或目录
  18. 【随机数生成算法系列】线性同余法和梅森旋转法
  19. 在 markdown 中使用表情符号
  20. 从零开始学习前端JAVASCRIPT — 1、JavaScript基础

热门文章

  1. powershell.exe直接运行命令
  2. JAVA的字符串拼接与性能
  3. windowsCE镜像文件结构
  4. spring随笔(二) AOP
  5. InputStreamReader 和 OutputStreamWriter类用法简介,及演示。
  6. 一个关于文件中位运算的的处理函数。
  7. 求解一元二次方程的简单c语言程序
  8. Golang list双向链表源码走读
  9. flink 任务执行类的加载
  10. 网页防篡改技术_阿里云云安全中心和web应用防火墙的网页防篡改功能有什么不同...