OO视角的重构技巧if\switch 的消除

基本结构:
private void Invoke(Class obj)
{
    
if typeof(obj)="x" then dosomethingX();
    
if typeof(obj)="y" then dosomethingY();
}

凡是符合这种结构的,都可以将dosomething移到obj中作为obj的一个成员,然后实现xClass,yClass,再采用如下方式调用
private void Invoke(Class obj)
{
    obj.dosomething()
}

扩展结构:
private void Invoke(Class obj)
{
    
if obj.name="x" then dosomethingX()
    
if obj.name="y" then dosomethingY()
}

这种结构的特点就是不再依赖于具体的类型来决定调用何种函数,而是依赖的该类的某个属性。
通常这样的处理,可以采用“化属性为分类”来处理,即重新设计xClass,yClass继承Class,再在xClass,yClass中分别实现dosomething,结果仍成为
   
private void Invoke(Class obj)
{
    obj.dosomething()
}

扩展结构与基本结构极其类似,实际上,基本结构是对隐含的typename的属性采用了简单的分类处理,而扩展结构是针对objname进行了分类处理。

再次扩展:
private void Invoke(Class obj)
{
    
if obj.name="xx" then dosomethingXX()
    
if obj.type="yy" then dosomethingYY()
    
if obj.role="zz" then dosomethingZZ()
}

前面的都是针对有统一属性的情况时的处理,大体上上面两种情况,可以解决所有的switch问题,那么,对于非统一属性的处理如何办理?这种仍然大量的if,写起来不但郁闷,维护也很麻烦,如果采用继承细化分类,则会造成更大的困扰。从继承的角度来说,实际上它的原理也就是在内部有一张表进行维护,根据不同的类型调用,会调用该表中指定的函数。

所以对于这样的情况,只要实现一张表,就可以更精细化地控制。

首先要结构一个类似的结构:

public class obj_method
{
    
public string name;
    
public string type;
    
public string role;
    
    
public dosomethingMethodHandle* dosomegthingMethod;
}

于是,我们就可以创建任意的条件来控制对象调用哪一种方法,在dotnet中,使用delegate直接解决MethodHandle问题,C++中亦有函数指针,所以这也不是问题,那么如果是java一类的语言,应该如何办?答案是实现一个接口IMethod,即:
public interface IMethod
{
    
void dosomething;
}

众所周所接口可以粘合类,所以,这里也是一样,Class本身要实现IMethod接口,obj_Method也要实用这样一个接口,然后在Class的dosomething调用obj_method的dosomething就行了。最后,仍然可以采用如下调用:
private void Invoke(Class obj)
{
    obj.dosomething()
}


更加复杂的扩展:

这种情况下,一般需要考虑状态机来实现一个逻辑管理了,并不是简单的继承或多态能轻易解决的。

总结
由此可以看出,真正避免if的方法是不存在的,但我们可以针对各种不同类型的情况,把需要自己写if的工作转移给框架或系统内部提供的机制来进行处理,这样,可以大大减少调用端代码的逻辑复杂度,从而显得代码更加清楚,实际上这是一种把细颗粒的逻辑放大成了类或对象之间的逻辑。通常情况下,调用端是实现逻辑表现最复杂的部分,所以为了平衡化,大多数时候是把调用端的逻辑复杂度往服务提供端转移,从而使项目中的代码达到更高的一致性,并整体上降低耦合性。
   直观地说,if/switch集中存在的地方往往就是一团疙瘩的地方,必要的逻辑疙瘩是不可解的,但是我们可以把它弄分散,弄平整,从而最大化保证整洁度。 
  
原文地址:https://www.cnblogs.com/William_Fire/p/956162.html