C# 一个计算器功能实现引发的思考
一.需求
计算器功能需求,这个众所周知,很明确了。
二.步骤分析
1)初级实现计算器
static int Calculator(int a,int b,string str) { switch(str) { case "+": return a + b; case "-": return a - b; case "*": return a * b; case "/": return a / b; } return 0; }
优势:代码简单。
劣势:如果新增需求,需要不断在switch中增加分支,并且需要在对应分支写上相应的逻辑代码。代码耦合度太高。违背对修改关闭原则。
2)中级实现计算器
I.先看case分支中对应的操作,都是运算。即,我们可以把其实现抽象出来。
II.因为我们知道所有的运算都是对两个数进行运算,所以,可以抽象出一个抽象类,即运算抽象基类BaseCalculate。
public abstract class BaseCalculate { public abstract int Calculate(int a, int b); } public class Add : BaseCalculate { public override int Calculate(int a, int b) { return a + b; } } public class Sub:BaseCalculate { public override int Calculate(int a, int b) { return a - b; } }
优势:这个操作,我们将case中分支的代码抽象出来了。在对应的运算子类中更改其操作就可以。将具体实现抽离出来。
劣势:代码量增加,违背了开放-封闭原则。(即开放增加,封闭修改原则)
上述,就是设计模式中,传说的简单工厂模式
3)高级实现计算器
class Program { static void Main(string[] args) { BaseFactory factory = new AddFactory(); Console.WriteLine(factory.GetCalculate().Calculate(2, 1)); BaseFactory factory2 = new SubFactory(); Console.WriteLine(factory2.GetCalculate().Calculate(2, 1)); Console.Read(); } } public abstract class BaseFactory { public abstract BaseCalculate GetCalculate(); } public class AddFactory:BaseFactory { public override BaseCalculate GetCalculate() { return new Add(); } } public class SubFactory:BaseFactory { public override BaseCalculate GetCalculate() { return new Sub(); } }
这就是传说中工厂方法模式,与上述简单工厂模式对比克服了开放-封闭原则。
优势:减去核心逻辑中的switch分支。
劣势:代码量又增加了。
4)扩展&补充
如果说上述的设计只为int型运算,如果现在需求增加,还需要增加 专门精度为float计算的计算器。上述计算,只针对int型,现在要专门是float型,该如何?
所以,我们只需要增加基类BaseFloatCalculate,然后进行各种实现。并在BaseFactory中增加 BaseFactory GetFloatCalculate() 即可。代码就不贴了,这其实就是扩展。
这就是抽象工厂模式。
即使上述种种,还是离不开switch分支问题,有可以解决分支问题的办法吗。有的,但是不算主流,可以利用反射。
BaseCalculate cal = (BaseCalculate)Assembly.Load("ConsoleApp7").CreateInstance("ConsoleApp7.Sub"); Console.WriteLine( cal.Calculate(2, 1));
三.总结
所谓优秀的功能的实现代码,即需要符合高聚酯,低耦合。
符合高聚酯,低耦合,那就离不开架构设定。
架构设计,其实无非就是即不断的抽象,对类抽象,对方法抽象。当然,也不能过度抽象,会造成冗余。
因此总结一下,架构设定,就是合理适度的抽象。
笔者认为
没有绝对适合某功能的架构框架,只有绝对合理适度的抽象。