简单工厂模式描述的是,通过类的继承关系,父类(工厂类)与子类(产品类),调用父类中的方法,实际干活儿的是子类中的方法;封装需求的不确定性,做出通用的编程,下面以常用的计算器为例:
最容易想到的写法是:
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段代码的第二段几乎是一样的,代码就足够通用了。
时间: 2024-10-29 03:24:49