zoukankan      html  css  js  c++  java
  • 设计模式之-简单工厂模式

    前言

    为了理解和学习简单工厂模式,我们先看一段简单计算器的代码

     class Program
        {
            static void Main(string[] args)
            {
                Console.Write("请输入数字A:");
                string A = Console.ReadLine();
                Console.Write("请选择运算符号(+、-、*、/):");
                string B = Console.ReadLine();
                Console.Write("请输入数字B:");
                string C = Console.ReadLine();
                string D = "";
                if (B == "+")
                    D = Convert.ToString(Convert.ToDouble(A) + Convert.ToDouble(C));
                if (B == "-")
                    D = Convert.ToString(Convert.ToDouble(A) - Convert.ToDouble(C));
                if (B == "*")
                    D = Convert.ToString(Convert.ToDouble(A) * Convert.ToDouble(C));
                if (B == "/")
                    D = Convert.ToString(Convert.ToDouble(A) / Convert.ToDouble(C));
                Console.WriteLine("结果是:" + D);
                Console.ReadKey();
            }
        }

    以上代码存在几点明显问题

    ①A、B、C、D这样的命名非常不规范,真实项目中应该避免使用

    ②if判断分支,让计算机多做了三次无用功

    ③除数的时候如果用户输入了非正数及符号,没有相关处理。

    根据上述三点问题进行优化后的代码如下:

     class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    Console.Write("请输入数字A:");
                    string strNumberA = Console.ReadLine();
                    Console.Write("请选择运算符号(+、-、*、/):");
                    string strOperate = Console.ReadLine();
                    Console.Write("请输入数字B:");
                    string strNumberB = Console.ReadLine();
                    string strResult = "";
                    switch (strOperate)
                    {
                        case "+":
                            strResult = Convert.ToString(Convert.ToDouble(strNumberA) + Convert.ToDouble(strNumberB));
                            break;
                        case "-":
                            strResult = Convert.ToString(Convert.ToDouble(strNumberA) - Convert.ToDouble(strNumberB));
                            break;
                        case "*":
                            strResult = Convert.ToString(Convert.ToDouble(strNumberA) * Convert.ToDouble(strNumberB));
                            break;
                        case "/":
                            if (strNumberB != "0")
                                strResult = Convert.ToString(Convert.ToDouble(strNumberA) / Convert.ToDouble(strNumberB));
                            else
                                strResult = "除数不能为0";
                            break;
                    }
                    Console.WriteLine("结果是:" + strResult);
                    Console.ReadKey();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("您的输入有错:" + ex.Message);
                }
            }
        }

    就上述代码而言,的确实现了简单计算器的功能,但是我们进一步思考这段代码,如果此时 需要新做一个计算器呢?估计有很多小伙伴灵光一现,复制粘贴大法。我们回想下古代活字印刷术的出现,对于印刷的巨大帮助。

    ⑴ 要改内容,只需要改动要改的文字,此为可维护

    ⑵这些字并非用完这次就无用了,以后的印刷中可以重复使用,此乃可复用

    ⑶若此版面内容要加字,只需要另刻字加入即可,这是可扩展

    ⑷字的排列可能是竖排,可能是横排,此时只需要将活字移动就可做到满足排列需求,此是灵活性好

    而再活字印刷术出现之前,以上四点特性都无法满足,要修改,必须重刻,要加字,必须重刻,要重新排列,必须重刻,印完这本后,此版已无任何可再利用价值。

    面向对象的好处

    ★业务的封装(让业务逻辑与界面逻辑分开,降低耦合度)

    根据上述思考,我们将运算单独封装一个运算类 Operation

    /// <summary>
        /// 运算类
        /// </summary>
        public class Operaion
        {
            /// <summary>
            /// 计算方法
            /// </summary>
            /// <param name="numberA">运算数</param>
            /// <param name="numberB">运算数</param>
            /// <param name="operate">符号</param>
            /// <returns>返回值</returns>
            public static double GetResult(double numberA, double numberB, string operate)
            {
                double result = 0d;
                switch (operate)
                {
                    case "+":
                        result = numberA + numberB;
                        break;
                    case "-":
                        result = numberA - numberB;
                        break;
                    case "*":
                        result = numberA * numberB;
                        break;
                    case "/":
                        result = numberA / numberB;
                        break;
                }
                return result;
            }
        }

    客户端调用的时候调用此方法即可:

    class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    Console.Write("请输入数字A:");
                    string strNumberA = Console.ReadLine();
                    Console.Write("请选择运算符号(+、-、*、/):");
                    string strOperate = Console.ReadLine();
                    Console.Write("请输入数字B:");
                    string strNumberB = Console.ReadLine();
                    string strResult = "";
                    //调用运算类中计算方法
                    strResult = Convert.ToString(Operaion.GetResult(Convert.ToDouble(strNumberA),
                        Convert.ToDouble(strNumberB), strOperate));
                    Console.WriteLine("结果是:" + strResult);
                    Console.ReadKey();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("您的输入有错:" + ex.Message);
                }
            }
        }

    上述代码实现了业务逻辑与界面的分离,但是还没有真正运用到程序的精髓所在:封装、继承、多态,带着思考和疑问,我们做出进一步修改如下:

     /// <summary>
        /// 运算类
        /// </summary>
        public class Operaion
        {
            private double _numberA = 0;
            private double _numberB = 0;
            public double NumberA
            {
                get { return _numberA; }
                set { _numberA = value; }
            }
            public double NumberB
            {
                get { return _numberB; }
                set { _numberB = value; }
            }
            public virtual double GetResult()
            {
                double result = 0;
                return result;
            }
        }
        /// <summary>
        /// 加法类,继承运算类
        /// </summary>
        class OpertionAdd : Operaion
        {
            public override double GetResult()
            {
                double result = 0;
                result = NumberA + NumberB;
                return result;
            }
        }
        /// <summary>
        /// 减法类,继承运算类
        /// </summary>
        class OperationSub : Operaion
        {
            public override double GetResult()
            {
                double result = 0;
                result = NumberA - NumberB;
                return result;
            }
        }
        /// <summary>
        /// 乘法类,继承运算类
        /// </summary>
        class OperationMul : Operaion
        {
            public override double GetResult()
            {
                double result = 0;
                result = NumberA * NumberB;
                return result;
            }
        }
    
        /// <summary>
        ///除法类,继承运算类
        /// </summary>
        class OperationDiv : Operaion
        {
            public override double GetResult()
            {
                double result = 0;
                if (NumberB == 0)
                    throw new Exception("除数不能为0.");
                result = NumberA / NumberB;
                return result;
            }
        }

    上述代码写完,此时就有一个疑问,如何让计算器知道我们希望用哪一个算法呢?

    下面我们看看简单运算工厂类

     public class OperationFactory
        {
            public static Operaion createOperate(string operate)
            {
                Operaion oper = null;
                switch (operate)
                { 
                    case "+":
                        oper = new OpertionAdd();
                        break;
                    case "-":
                        oper = new OperationSub();
                        break;
                    case "*":
                        oper = new OperationMul();
                        break;
                    case "/":
                        oper = new OperationDiv();
                        break;
                }
                return oper;
            }
    
        }

    有了运算工厂类,我们只需要输入运算符号,工厂就能实例化适合的对象,通过多态,返回父类的方法实现了计算器的结果,客户端代码如下:

    class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    Console.Write("请输入数字A:");
                    string strNumberA = Console.ReadLine();
                    Console.Write("请选择运算符号(+、-、*、/):");
                    string strOperate = Console.ReadLine();
                    Console.Write("请输入数字B:");
                    string strNumberB = Console.ReadLine();
                    //调用工厂类进行计算
                    Operaion oper;
                    oper = OperationFactory.createOperate(strOperate);
                    oper.NumberA =double.Parse(strNumberA);
                    oper.NumberB =double.Parse(strNumberB);
                    //返回计算结果
                    var  strResult = oper.GetResult();
                    Console.WriteLine("结果是:" + strResult);
                    Console.ReadKey();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("您的输入有错:" + ex.Message);
                }
            }
        }

    这样,不管我们是控制台程序、Windows程序,Web程序或者手机程序,都可以使用这段代码来实现计算器的功能,如果有一天我们需要更改加法运算,我们改OperationAdd就可以了,如果需要增加其他复杂运算,比如平方根、立方根,我们只需要增加相应的运算子类和运算类工厂,再switch中增加分支即可。

    UML类图

  • 相关阅读:
    Dapper的基本 理论 知识
    路由
    WebForm+一般处理程序+Ajax聊天
    Jquer + Ajax 制作上传图片文件
    (3.4)表相关操作之完整性约束
    (3.3)表相关操作之数据类型
    (3.2)表相关操作之表的增删改查
    (3.1)表相关操作之存储引擎介绍
    常用模块
    模块与包
  • 原文地址:https://www.cnblogs.com/zhangxiaoyong/p/7199593.html
Copyright © 2011-2022 走看看