大话设计模式学习之简单工厂模式与工厂方法模式的学习

简单工厂模式与工厂方法模式的对比

简单工厂模式:

UML图

 

首先来解释一下这个UML图

1、运算类是一个基类,包含了两个属性,一个虚方法getResult

2、加法类,减法类,乘法类,除法类分别继承于基类运算类,并且根据不同的类实例化出不同的虚方法getResult从而实现了多态

3、简单工厂类继承于运算类,主要封装了业务逻辑,根据不同的操作符实例化出不同的派生类(加法类、减法类、乘法类、除法类)。

下面是源码分析:

第一步:创建基类

#region 基类

    class Operation

    {

        private double _number1;

        private double _number2;

        public double Number1

        {

            get { return this._number1; }

            set { this._number1 = value; }

        }

        public double Number2

        {

            get { return this._number2; }

            set { this._number2 = value; }

        }

        public virtual double getResult()

        {

            double result = 0;

            return result;

        }

    }

#endregion

第二步:创建派生类

#region 四个派生类:加法类,减法类,乘法类,除法类

    class OperationAdd : Operation

    {

        public override double getResult()

        {

            double result = Number1 + Number2;

            return result;

        }

    }

    class OperationSub : Operation

    {

        public override double getResult()

        {

            double result = Number1 - Number2;

            return result;

        }

    }

    class OperationMul : Operation

    {

        public override double getResult()

        {

            double result = Number1 * Number2;

            return result;

        }

    }

    class OperationDiv : Operation

    {

        public override double getResult()

        {

            double result = Number1 / Number2;

            return result;

        }

    }

    #endregion

第三步:创建简单工厂类

#region 工厂类

    class OperationFactory : Operation

    {

 

        public static Operation createOperation(string strOperate)

        {

            Operation oper = null;

            switch (strOperate)

            {

                case "+":

                    oper = new OperationAdd();

                    break;

                case "-":

                    oper = new OperationSub();

                    break;

                case "*":

                    oper = new OperationMul();

                    break;

                case "/":

                    oper = new OperationDiv();

                    break;

            }

            return oper;

        }

    }

    #endregion

好啦现在我们在Main函数中使用它们

class Program

    {

        static void Main(string[] args)

        {

            Console.WriteLine("请输入第一数字");

            string strNumber1 = Console.ReadLine();

            Console.WriteLine("请输入第二个数字");

            string strNumber2 = Console.ReadLine();

            Console.WriteLine("请输入操作符");

            string strOperate = Console.ReadLine();

            Operation oper = OperationFactory.createOperation(strOperate);//实例化对象

            //为实例化的Operation对象传递了两个属性值

            oper.Number1 = double.Parse(strNumber1);

            oper.Number2 = double.Parse(strNumber2);

            double result=oper.getResult();

            Console.WriteLine(result.ToString());

            Console.ReadKey();

        }

      

    }

运行结果如下:

 

从我们使用的Main函数我们可以看出,我们并没有任何的业务逻辑结构在里面,只是传递了两个属性变量和一个操作符,而客户端并不需要知道Operation到底做了什么,所有的业务逻辑封装到了Operation类及其派生类中。这样做将业务逻辑层和表现层很好的分离了。注意业务和表现层很好的分离。这是一个很伟大的思想,因为它让我们可以很好的重用这些代码,或者说可维护性很强。比如:网站建设中:后台代码与前台代码的分离,WPF中XAML语言与后台C#逻辑的分离等等。

好啦,现在我们来看一下比简单工厂更加神奇的工厂方法模式

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

UML图

 

如图所示:我们把工厂类抽象为一个接口,这个接口只有一个方法,就是创建抽象产品的工厂方法。然后所有要生成具体类的工厂,就去实现这个接口。

下面是源码分析:

第一步:基类设计

    #region 基类

    class Operation

    {

        private double _number1;

        private double _number2;

        public double Number1

        {

            get { return this._number1; }

            set { this._number1 = value; }

        }

        public double Number2

        {

            get { return this._number2; }

            set { this._number2 = value; }

        }

        //创建一个虚方法

        public virtual double getResult()

        {

            double result = 0;

            return result;

        }

    }

#endregion

第二步:派生类设计

    #region 派生类继承于基类Operation,并分别重写了虚方法

    class OperationAdd : Operation

    {

        public override double getResult()

        {

            double result = Number1 + Number2;

            return result;

        }

    }

    class OperationSub : Operation

    {

        public override double getResult()

        {

            double result = Number1 - Number2;

            return result;

        }

    }

    class OperationMul : Operation

    {

        public override double getResult()

        {

            double result = Number1 * Number2;

            return result;

        }

    }

    class OperationDiv : Operation

    {

        public override double getResult()

        {

            double result = Number1 / Number2;

            return result;

        }

    }

    #endregion

第三步:创建一个接口,抽象工厂,所有的派生工厂类都实现这个接口

    #region 抽象工厂

    //创建一个接口

    interface IOperationFactory

    {

        Operation createOperation();

    }

    #endregion

第四步:派生工厂类设计

#region 派生工厂类 真正实例化了Operation对象

    //该类为加法工厂类,继承于父类OperationFactory,并实例化createOperation方法并输入OperationAdd对象

    class OperationFactoryAdd : IOperationFactory

    {

        public Operation createOperation()

        {

            return new OperationAdd();

        }

    }

    //该类为减法工厂类,继承于父类OperationFactory,并实例化createOperation方法输出OperationSub对象

    class OperationFactorySub : IOperationFactory

    {

        public Operation createOperation()

        {

            return new OperationSub();

        }

    }

    //该类为乘法工厂类,继承于父类OperationFactory,并实例化createOperation方法输出OperationMul对象

    class OperationFactoryMul : IOperationFactory

    {

        public Operation createOperation()

        {

            return new OperationMul();

        }

    }

    //该类为除法工厂类,继承于父类OperationFactory,并实例化createOperation方法输出OperationDiv对象

    class OperationFactoryDiv : IOperationFactory

    {

        public Operation createOperation()

        {

            return new OperationDiv();

        }

    }

    #endregion

通过派生的工厂类,我们实际上实例化了Operation对象

下面我们来看下客户端代码实现:

class Program

    {

        static void Main(string[] args)

        {

            Console.WriteLine("请输入两个数字");

            string strNumber1 = Console.ReadLine();

            string strNumber2 = Console.ReadLine();

            double douNumber1 = double.Parse(strNumber1);

            double douNumber2 = double.Parse(strNumber2);

            //先实例化一个工厂方法再创建Operation派生对象

            IOperationFactory operFactory = new OperationFactoryAdd();//实例化了一个加法工厂

            Operation objOperation = operFactory.createOperation();//从加法工厂类得到实例的求平均值类

            objOperation.Number1 = douNumber1;//给Operation的两个属性赋值

            objOperation.Number2 = douNumber2;

            //调用getResult方法

            double result=objOperation.getResult();

            Console.WriteLine(result.ToString());

            Console.ReadKey();

        }

    }

从客户端实现代码我们可以看出 :首先实例化了一个抽象工厂接口,再由实例化得到的工厂类去得到对应的实例化的Operation派生类。

我们大家可以看到,工厂方法模式与简单工厂模式有着一定的相似性,虽然两者实现了相同的功能(记住千万不要拿实现功能就OK来评价一个程序或者代码设计,那是很不负责的一种态度。而要在功能实现的基础上考虑程序的健壮性,可扩展性,可重用性等)同时工厂方法模式明显比简单工厂模式要复杂的多。那么为什么我们就用简单工厂就可以完成任务行吗?

好啦,如果我们的需求变了,需要再添加一个功能,比如说求两个数的平均值。

简单工厂模式的做法是:

在基类下派生出一个新的类出来,同时必须还要改的一个地方是简单工厂类,在这里面加上一个case的判断,但是这明显是在修改逻辑代码。类的设计原则是不应该修改类的结构或者代码。它违背了Open-Close原则,模式的设计只能对类进行扩展,不能对类进行修改。就好比我们计算机的插槽,CPU只提供了接口,我们要插什么只要在外部插上需要的硬件就行啦,而我们并不能修改CPU里面的结构等其他东西。这就保证了CPU内部工作的稳定性。同样这也是一样的,Open-Close原则也在一定的程度上保证了类设计的稳定性。

那么如果工厂方法模式的做法是:

在基类下派生出一个新的类,同时,在抽象工厂中派生出新的工厂方法。这两个类的设计都只是扩展了原有的类或者接口的设计,并没有去修改原有的类或者结构。

所以工厂方法模式是简单工厂模式的进一步抽象和推广。

 

好啦今天就总结到这里:详细内容请大家查阅大话设计模式或者GOF书籍

 

posted @ 2013-05-03 21:55  罗导  阅读(270)  评论(0编辑  收藏  举报