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

    简单工厂模式描述的是,通过类的继承关系,父类(工厂类)与子类(产品类),调用父类中的方法,实际干活儿的是子类中的方法;封装需求的不确定性,做出通用的编程,下面以常用的计算器为例:

    最容易想到的写法是:

     1            Console.WriteLine("请输入操作数1:");
     2             double a = double.Parse(Console.ReadLine());
     3             Console.WriteLine("请输入操作符:");
     4             string opt = Console.ReadLine();
     5             Console.WriteLine("请输入操作数2:");
     6             double b = double.Parse(Console.ReadLine());
     7 
     8             double result = 0;
     9 
    10             switch (opt)
    11             {
    12                 case "+":
    13                     result = a + b;
    14                     break;
    15                 case "-":
    16                     result = a - b;
    17                     break;
    18                 case "*":
    19                     result = a * b;
    20                     break;
    21                 case "/":
    22                     if (b == 0)
    23                     {
    24                         throw new Exception("被除数不能为0");
    25                     }
    26                     result = a / b;
    27                     break;
    28             }
    29             Console.WriteLine("计算结果是:"+result);

    这么写,对于控制台来说基本够用了,但是它有很多的弊病:

    1.计算结果是直接输出到控制台,如果要做一个WinForm版呢?(目前只有重新写一遍,不能够重用)

    2.这里的case只考虑了基本的四则运算,业务变更后,如果有求平方、求立方、开方等运算呢?(那么只能去改写好的方法,一个项目中只有一处还好说,如果有多处要修改,那就麻烦了,可扩展性太差)
    3.这段代码也没有体现面向对象的3大特性:封装、继承、多态。

    基于以上的种种弊端,需要修改代码:

    首先定义一个父类Operat,在类中不考虑未来是否有四则运算及怎样运算

    Operat类
     1 /// <summary>
     2     /// 父类计算方法
     3     /// </summary>
     4     public class Operat
     5     {
     6         public double NumberA { get; set; }
     7         public double NumberB { get; set; }
     8         /// <summary>
     9         /// 构造函数
    10         /// </summary>
    11         /// <param name="a"></param>
    12         /// <param name="b"></param>
    13         public Operat(double a,double b)
    14         {
    15             this.NumberA = a;
    16             this.NumberB = b;
    17         }
    18 
    19         public virtual double Oper()
    20         {
    21             double result = 0;
    22             return result;
    23         }
    24     }

    只定义了2个操作数和一个计算方法(虚方法,因为这里不知道未来有几个运算)

    再定义一个加法类(OperatAdd)来继承它,并实现父类中的计算方法:

    OperatAdd类(加法)
     1  class OperatAdd : Operat
     2     {
     3         //构造函数
     4         public OperatAdd(double a,double b):base(a,b)
     5         {
     6 
     7         }
     8         /// <summary>
     9         /// 子类重写父类的Oper方法(实现)
    10         /// </summary>
    11         /// <returns></returns>
    12         public override double Oper()
    13         {
    14             double result = 0;
    15             result = NumberA + NumberB;
    16             return result;
    17         }
    18     }

    依次定义后面的3个类(减、乘、除)

    OperatSub类(减法)
     1 class OperatSub : Operat
     2     {
     3         public OperatSub(double a,double b):base(a,b)
     4         {
     5 
     6         }
     7         public override double Oper()
     8         {
     9             double result = 0;
    10             result= NumberA - NumberB;
    11             return result;
    12         }
    13     }
    OperatMult类(乘法)
     1 class OperatMult:Operat
     2     {
     3         public OperatMult(double a,double b):base(a,b)
     4         {
     5 
     6         }
     7         public override double Oper()
     8         {
     9             double result = 0;
    10             result= NumberA * NumberB;
    11             return result;
    12         }
    13     }

    OperatVision类(除法)

     1 class OperatVision:Operat
     2     {
     3         public OperatVision(double a,double b):base(a,b)
     4         {
     5 
     6         }
     7         public override double Oper()
     8         {
     9             double result = 0;
    10             if (NumberB==0)
    11             {
    12                 throw new Exception("被除数不能为0");
    13             }
    14             result = NumberA / NumberB;
    15             return result;
    16         }
    17     }

    这时候,应该考虑的问题是,在业务中,怎样调用这4个子类中的运算方法(简单工厂)

    定义一个工厂类,由工厂类根据具体业务去调用具体的子类(产品类)

     1 /// <summary>
     2     /// 工厂类
     3     /// </summary>
     4    public class OperatFactory
     5     {
     6         public Operat JiSuan(double a, string opt, double b)
     7         {
     8             Operat opt1 = null;
     9             //封装了异同业务需求的差异
    10             switch (opt)
    11             {
    12                 case "+":
    13                     opt1 = new OperatAdd(a, b);     //产品1(加法)
    14                     break;
    15                 case "-":
    16                     opt1 = new OperatSub(a, b);    //产品2(减法)
    17                     break;
    18                 case "*":
    19                     opt1 = new OperatMult(a, b);   //产品3(乘法)
    20                     break;
    21                 case "/":
    22                     opt1 = new OperatVision(a, b);  //产品4(除法)
    23                     break;
    24             }
    25             return opt1;        //返回父类对象
    26         }
    27     }

    给opt赋不同的运算,工厂类就会去调用相应的子类,执行计算方法,new出相应的产品类,因为子类中都只是 return result;没有考虑这个结果具体显示在那个地方(控制台还是winform中的label),就变得相当灵活了,并返回父类对象。

    控制台去使用时,调用工厂类中JiSuan()方法返回父类对象,即可:

     1          Console.WriteLine("请输入操作数1:");
     2             double a = double.Parse(Console.ReadLine());
     3             Console.WriteLine("请输入操作符:");
     4             string opt = Console.ReadLine();
     5             Console.WriteLine("请输入操作数2:");
     6             double b = double.Parse(Console.ReadLine());
     7 
     8             OperatFactory factory = new OperatFactory();
     9             Operat opt1 = factory.JiSuan(a, opt, b);
    10             Console.WriteLine("计算结果是:{0}", opt1.Oper());
    11             Console.ReadKey();

    而winform的代码也很类似:

     1             lbResult.Text = "";
     2 
     3             lbResult.ForeColor = Color.Red;
     4             lbResult.Font = new Font("宋体", 12);
     5             double a = double.Parse(txtNumber1.Text.Trim());
     6             string opt = cmbOperat.SelectedItem.ToString();
     7             double b = double.Parse(txtNumber2.Text.Trim());
     8 
     9             OperatFactory factory = new OperatFactory();
    10             Operat oper = factory.JiSuan(a, opt, b);
    11             lbResult.Text = oper.Oper().ToString();

    可以看出上面2段代码的第二段几乎是一样的,代码就足够通用了。

     
  • 相关阅读:
    Bonding
    负载均衡
    XML
    wireshark
    IE
    轨迹系列7——Socket总结及实现基于TCP或UDP的809协议方法
    轨迹系列6——车载GPS对接方案汇总小结(809、自定义协议、前置库、WS)
    基于R树索引的点面关系判断以及效率优化统计
    WebGIS中以version方式实现代码更新后前端自动读取更新代码的方法
    轨迹系列5——验证轨迹GPS坐标转换为本地坐标的四/七参数是否准确的一种方案
  • 原文地址:https://www.cnblogs.com/chens2865/p/3732071.html
Copyright © 2011-2022 走看看