zoukankan      html  css  js  c++  java
  • 【转载】创建型工厂方法模式

    介绍:
    简单工厂模式中,我们提到,工厂方法模式是简单工厂模式的一个延伸,它属于Gof23中设计模式的创建型设计模式。它解决的仍然是软件设计中与创建对象有关的问题。它可以更好的处理客户的需求变化。

    引入
    我们继续来说"new"的问题,我们在简单工厂模式中,将实例化对象的工作推迟到了专门负责创建对象的工厂类中,这样,在我们事先预知的情况下,可以根据我们的需要动态创建产品类。但是,我们的预知是有限的,客户的变化可能是无限的。所以,就出现了问题,一旦客户的变化超越了我们的预知,我们就必须修改我们的源代码了。这是设计模式所不允许的,怎么办呢?工厂方法模式正是解决此类问题的。
    问题:具体工厂类的创建工作不能满足我们的要求了,创建的工作变化了
    解决思路:哪里变化,封装哪里。把具体工厂封装起来。

    定义
    工厂方法模式又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂模式(Polymorphic Factory),在工厂方法模式中,父类负责定义创建对象的公共接口,而子类则负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类中完成,即由子类来决定究竟应该实例化(创建)哪一个类。

    意图
    定义一个用户创建对象的接口,让子类决定实例化哪一个类,工厂方法模式使一个类的实例化延迟到其子类。

    参与者

    • 抽象产品角色(Product)
      定义产品的接口
    • 具体产品角色(ConcreteProduct)
      实现接口Product的具体产品类
    • 抽象工厂角色(Creator)
      声明工厂方法(FactoryMethod),返回一个产品
    • 真实的工厂(ConcreteCreator)
      实现FactoryMethod工厂方法,由客户调用,返回一个产品的实例

    工厂方法模式UML图
    工厂方法模式UML图

    现实生活中的例子
    为了方便大家理解,我仍然举穿衣服方面的一个例子。这个例子与简单工厂模式中的那个例子有些不同。
    据说清朝有个皇帝穿衣非常的奢侈,每种衣服(具体产品类)由一宫女(具体工厂类)专门负责,这样一来,每增加一种衣服(具体产品类),就要多出一个宫女(具体工厂类),但是他们各负其责,互不影响。皇帝之所以这样做,是因为针对穿衣服这件事来说,可扩展性是非常强的()。

    分析
    实现的功能:可以根据皇帝的要求,动态的创建(由宫女去拿)已存在的具体产品(衣服),如果皇帝的要求太苛刻,这种衣服还没有,只需要增加一个宫女,一个衣服就能够满足他的要求了。每个宫女只负责一种衣服(高内聚),要增加一种衣服,对于以前的所有宫女与衣服来说,都不会受到影响(设计模式中所期望的)。说到这里,是不是明白了工厂方法模式所能解决的问题及其应用了?呵呵。。你一定在想,比简单工厂模式灵活性高吧。。

    抽象工厂角色代码

     1namespace FactoryMethod
     2{
     3    /**//// <summary>
     4    /// 抽象工厂类,定义产品的接口
     5    /// </summary>
     6    public interface IFactory
     7    {
     8        ICoat CreateCoat();
     9    }
    10}

    抽象产品角色代码

     1namespace FactoryMethod
     2{
     3    /// <summary>
     4    /// 抽象产品类
     5    /// </summary>

     6    public interface ICoat
     7    {
     8        void ShowCoat();
     9    }

    10}

    具体工厂角色代码

     1namespace FactoryMethod
     2{
     3    /// <summary>
     4    /// 具体工厂类:用于创建商务上衣类
     5    /// </summary>

     6    public class BusinessFactory:IFactory
     7    {        
     8        public ICoat CreateCoat()
     9        {
    10            return new BusinessCoat();
    11        }

    12    }

    13
    14    /// <summary>
    15    /// 具体工厂类,用于创建时尚上衣
    16    /// </summary>

    17    public class FashionFactory : IFactory
    18    {
    19        public ICoat CreateCoat()
    20        {
    21            return new FashionCoat();
    22        }

    23    }

    24}

    具体产品角色代码

     1namespace FactoryMethod
     2{
     3    /// <summary>
     4    /// 具体产品类,商务上衣类
     5    /// </summary>

     6    public class BusinessCoat:ICoat
     7    {
     8        public void ShowCoat()
     9        {
    10            Console.WriteLine("这件是商务上衣");
    11        }

    12    }

    13
    14    /// <summary>
    15    /// 具体产品类,时尚上衣类
    16    /// </summary>

    17    public class FashionCoat : ICoat
    18    {
    19        public void ShowCoat()
    20        {
    21            Console.WriteLine("这件是时尚上衣");
    22        }

    23    }

    24}

    25

    客户端代码

     1namespace FactoryMethod
     2{
     3    /// <summary>
     4    /// 客户端代码
     5    /// </summary>

     6    class Client
     7    {
     8        static void Main(string[] args)
     9        {
    10            //为了方便以后修改,将工厂类的类名写在应用程序配置文件中
    11            string factoryName = ConfigurationManager.AppSettings["FactoryName"];
    12          
    13            IFactory factory = (IFactory)Assembly.Load("ConcreteFactory").CreateInstance("FactoryMethod." + factoryName);
    14            
    15            ICoat coat = factory.CreateCoat();
    16            //显示你要的上衣
    17            coat.ShowCoat();
    18        }

    19    }

    20}

    客户端代码需要注意的两个地方:
    1,把具体工厂类类名称写在了应用程序配置文件中,方便修改
    2,用到了反射,利用.NET提供的反射可以根据类名来创建它的实例,非常方便


    由反射想到的:
    下面这一段内容不是计划要写的。
    如果在具体工厂中,每次new的对象都是一个,而且这些类是继承自抽象产品接口的,那么我们用简单工厂模式也可以实现动态的增加具体产品类。这样来做,在简单工厂模式中最核心的部分----工厂类不要根据传来的条件去动态创建产品类,利用反射机制去创建。把要实例化的类名放在应用程序配置文件中,呵呵。。这样利用.NET特有的反射就可以用简单工厂模式解决更多的问题了,工厂方法模式的一部分问题也是可以通过“这样的简单工厂模式”解决的,在需要增加具体产品类时,不用增加具体工厂,是不是简单一些呀。下去试一下。。。

    优点:

    • 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象。而且如何创建一个具体产品的细节完全封装在具体工厂内部,符合高内聚,低耦合。
    • 在系统中加入新产品时,无需修改抽象工厂和抽象产品提供的接口,无需修改客户端,也无需修改其他的具体工厂和具体产品,很好的利用了封装和委托。

    缺点:

    • 在添加新产品时,需要编写新的具体产品类(其实这不算一个缺点,因为这是不可避免的),要增加与之对应的具体工厂类。

    应用情景:

    • 类不知道自己要创建哪一个对象时
    • 类用它的子类来指定创建哪个对象
    • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候  

    工厂方法模式在ASP.NET HTTP通道中的应用,TerryLee在他的那篇文件中写的非常好,推荐去看一下。

  • 相关阅读:
    pat 甲级 1065. A+B and C (64bit) (20)
    pat 甲级 1064. Complete Binary Search Tree (30)
    pat 甲级 1010. Radix (25)
    pat 甲级 1009. Product of Polynomials (25)
    pat 甲级 1056. Mice and Rice (25)
    pat 甲级 1078. Hashing (25)
    pat 甲级 1080. Graduate Admission (30)
    pat 甲级 团体天梯 L3-004. 肿瘤诊断
    pat 甲级 1099. Build A Binary Search Tree (30)
    Codeforce 672B. Different is Good
  • 原文地址:https://www.cnblogs.com/Loyalty/p/2469050.html
Copyright © 2011-2022 走看看