zoukankan      html  css  js  c++  java
  • 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集中存在的地方往往就是一团疙瘩的地方,必要的逻辑疙瘩是不可解的,但是我们可以把它弄分散,弄平整,从而最大化保证整洁度。 
      
  • 相关阅读:
    WTL for Visual Studio 2012 配置详解
    自己动手让Visual Studio的Win32向导支持生成对话框程序
    改造联想Y480的快捷键(跨进程替换窗口过程(子类化)的实现——远程线程注入)
    Visual Studio 2012 Ultimate RTM 体验(附下载地址和KEY)
    VC++实现获取文件占用空间大小的两种方法(非文件大小)
    为Visual Studio添加默认INCLUDE包含路径一劳永逸的方法(更新)
    Winsdows 8 环境下搭建Windows Phone 开发环境
    Linq to Visual Tree可视化树的类Linq查询扩展API(译)
    检测元素是否在界面可显示区域
    Debug the Metro Style App:Registration of the app failed
  • 原文地址:https://www.cnblogs.com/William_Fire/p/956162.html
Copyright © 2011-2022 走看看