设计模式之-简单工厂模式

简介: 前言 为了理解和学习简单工厂模式,我们先看一段简单计算器的代码 class Program { static void Main(string[] args) { Console.

前言

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

 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类图

 

  • 感谢你的阅读。如果你觉得这篇文章对你有帮助或者有启发,就请推荐一下吧~你的精神支持是博主强大的写作动力。欢迎转载!
  • 博主的文章没有高度、深度和广度,只是凑字数。由于博主的水平不高(其实是个菜B),不足和错误之处在所难免,希望大家能够批评指出。
  • 欢迎加入.NET 从入门到精通技术讨论群→523490820 期待你的加入
  • 不舍得打乱,就永远学不会复原。被人嘲笑的梦想,才更有实现的价值。
  • 我的博客:http://www.cnblogs.com/zhangxiaoyong/
目录
相关文章
|
6天前
|
设计模式 算法 安全
设计模式——模板模式
模板方法模式、钩子方法、Spring源码AbstractApplicationContext类用到的模板方法
设计模式——模板模式
|
1月前
|
设计模式
设计模式-单一职责模式
设计模式-单一职责模式
|
1月前
|
设计模式 XML 存储
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
文章详细介绍了工厂方法模式(Factory Method Pattern),这是一种创建型设计模式,用于将对象的创建过程委托给多个工厂子类中的某一个,以实现对象创建的封装和扩展性。文章通过日志记录器的实例,展示了工厂方法模式的结构、角色、时序图、代码实现、优点、缺点以及适用环境,并探讨了如何通过配置文件和Java反射机制实现工厂的动态创建。
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
|
1月前
|
设计模式 XML Java
【一】设计模式~~~创建型模式~~~简单工厂模式(Java)
文章详细介绍了简单工厂模式(Simple Factory Pattern),这是一种创建型设计模式,用于根据输入参数的不同返回不同类的实例,而客户端不需要知道具体类名。文章通过图表类的实例,展示了简单工厂模式的结构、时序图、代码实现、优缺点以及适用环境,并提供了Java代码示例和扩展应用,如通过配置文件读取参数来实现对象的创建。
【一】设计模式~~~创建型模式~~~简单工厂模式(Java)
|
1月前
|
设计模式 uml C语言
设计模式----------工厂模式之简单工厂模式(创建型)
这篇文章详细介绍了简单工厂模式,包括其定义、应用场景、UML类图、通用代码实现、运行结果、实际应用例子,以及如何通过反射机制实现对象创建,从而提高代码的扩展性和维护性。
设计模式----------工厂模式之简单工厂模式(创建型)
|
1月前
|
设计模式 uml
设计模式-------------工厂模式之工厂方法模式(创建型)
工厂方法模式是一种创建型设计模式,它通过定义一个用于创建对象的接口,让子类决定实例化哪一个类,从而实现类的实例化推迟到子类中进行,提高了系统的灵活性和可扩展性。
|
1月前
|
设计模式 测试技术 Go
[设计模式]创建型模式-简单工厂模式
[设计模式]创建型模式-简单工厂模式
|
2月前
|
设计模式 算法 Java
跟着GPT学设计模式之模板模式
模板模式是一种行为型设计模式,它定义了一个操作中的算法骨架,将一些步骤的具体实现延迟到子类中。该模式使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
44 6
|
1月前
|
设计模式 人工智能 达摩院
设计模式的基础问题之模板模式在软件开发中的优势是什么
设计模式的基础问题之模板模式在软件开发中的优势是什么
|
1月前
|
设计模式 项目管理
设计模式的基础问题之生成器模式在项目管理应用的问题如何解决
设计模式的基础问题之生成器模式在项目管理应用的问题如何解决