• 设计模式之工厂模式


    概述:

    在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。如何应对这种变化?提供一种封装机制来隔离出“这个易变对象”的变化,从而保持系统中“其它依赖该对象的对象”不随着需求的改变而改变?这就是要说的Factory Method模式了。 

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

    UML图:

    工厂方法解说 

      在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不接触哪一个产品类被实例化这种细节。这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。在Factory Method模式中,工厂类与产品类往往具有平行的等级结构,它们之间一一对应。

    下面仍以计算器例子来说明,

    运算类和简单工厂中一样,

    /// <summary>
        /// 抽象运算类
        /// </summary>
        public abstract class Operation
        {
            private double _numA = 0;
    
            public double NumA
            {
                get { return _numA; }
                set { _numA = value; }
            }
            private double _numB = 0;
    
            public double NumB
            {
                get { return _numB; }
                set { _numB = value; }
            }
    
            /// <summary>
            /// 运算方法
            /// </summary>
            /// <returns></returns>
            public virtual double GetResult()
            {
                double result = 0;
                return result;
            }
        }
    
    /// <summary>
        /// 加法运算类
        /// </summary>
        public class OperationAdd : Operation
        {
            public override double GetResult()
            {
                return NumA + NumB;
            }
        }
    
        /// <summary>
        /// 除法运算
        /// </summary>
        public class OperationDiv : Operation
        {
            public override double GetResult()
            {
                if (NumB == 0)
                {
                    throw new Exception("除数不能为0!");
                }
                else
                    return NumA / NumB;
            }
        }
    View Code

     声明一个工厂接口

        /// <summary>
        /// 工厂接口
        /// </summary>
        interface IFactory
        {
            Operation CreateOperation();
        }

    有了工厂接口,现在创建具体的工厂类,只创建两个比较简单的

      /// <summary>
        /// 加法工厂类
        /// </summary>
        class AddFactory : IFactory
        {
            public Operation CreateOperation()
            {
                return new OperationAdd();
            }
        }
        /// <summary>
        /// 除法工厂类
        /// </summary>
        class DivFactory : IFactory
        {
            public Operation CreateOperation()
            {
                return new OperationDiv();
            }
        }

     这样通过工厂方法模式我们把上面那对象创建工作封装在了工厂中,此时我们似乎完成了整个Factory Method的过程。这样达到了我们应用程序和具体计算对象之间解耦的目的了吗?看一下此时客户端程序代码:

      class Program
        {
            static void Main(string[] args)
            {
                IFactory operFactory = new AddFactory();
                Operation oper = operFactory.CreateOperation();
                oper.NumA = 1;
                oper.NumB = 2;
                Console.WriteLine(oper.GetResult());
    
                Thread.Sleep(3000);
            }
        }

     在客户程序中,我们有效地避免了具体产品对象和应用程序之间的耦合,可是我们也看到,增加了具体工厂对象和应用程序之间的耦合。那这样究竟带来什么好处呢?在引进新产品(计算方法)的情况下,我们并不需要去修改工厂类,而只是增加新的产品类和新的工厂类(注意:这是任何时候都不能避免的),整个工厂和产品体系其实都每一修改的变化,只有扩展的变化,这样很好的符合了开放封闭原则。

    实现要点:

    1. Factory Method模式的两种情况:一是Creator类是一个抽象类且它不提供它所声明的工厂方法的实现;二是Creator是一个具体的类且它提供一个工厂方法的缺省实现。 

    2. 工厂方法是可以带参数的。 

    3. 工厂的作用并不仅仅只是创建一个对象,它还可以做对象的初始化,参数的设置等。 

    效果 

    1. 用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。 

    2. Factory Method模式通过面向对象的手法,将所要创建的具体对象的创建工作延迟到了子类,从而提供了一种扩展的策略,较好的解决了这种紧耦合的关系。 

    适用性 

    在以下情况下,适用于工厂方法模式: 

    1. 当一个类不知道它所必须创建的对象的类的时候。

    2. 当一个类希望由它的子类来指定它所创建的对象的时候。 

    3. 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。 

    总结 
        Factory Method模式是设计模式中应用最为广泛的模式,通过本文,相信读者已经对它有了一定的认识。然而我们要明确的是:在面向对象的编程中,对象的创建工作非常简单,对象的创建时机却很重要。Factory Method要解决的就是对象的创建时机问题,它提供了一种扩展的策略,很好地符合了开放封闭原则。

    推荐阅读:创建型模式篇-工厂方法模式(Factory Method)

  • 相关阅读:
    Linux基础命令-cd
    grep和egrep正则表达式
    SpringMVC源码阅读-一个请求主要处理流程DispatcherServlet(四)
    SpringMVC源码阅读-dispatcher组件初始化过程(三)
    SpringMVC源码阅读-Servlet WebApplicationContext初始化(二)
    SpringMVC源码阅读-Root WebApplicationContext初始化(一)
    logback源码阅读-配置文件解析过程(六)
    logback源码阅读-Encoder(五)
    logback源码阅读-Appender(四)
    logback源码阅读-Logger日志生成(三)
  • 原文地址:https://www.cnblogs.com/panshirui/p/3745872.html
Copyright © 2020-2023  润新知