首页 > 代码库 > 23种设计模式之简单工厂

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段代码的第二段几乎是一样的,代码就足够通用了。