面向对象的六大设计原则(四):终结篇

四、接口隔离原则:Interface Segregation Principle(ISP)

       定义:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。这个原则比较简单很好理解,但熟练使用却不简单。如何适度的使用接口,需要我们进行反复的思考与设计,才能很好的实践这一原则。这就好像我们的笔记本电脑,一般只会有USB、HDMI、VGA和网线接口。简简单单的几个接口,支持设备的接入,网络连接,视频投影。再多的话,就会造成接口冗余,少了的话, 又无法满足现实所需。

       接下来我们看些Android中的一些源码

    public interface OnClickListener {
        /**
         * Called when a view has been clicked.
         *
         * @param v The view that was clicked.
         */
        void onClick(View v);
    }
    
    public interface OnLongClickListener {
        /**
         * Called when a view has been clicked and held.
         *
         * @param v The view that was clicked and held.
         *
         * @return true if the callback consumed the long click, false otherwise.
         */
        boolean onLongClick(View v);
    }
    


这是Android中我们经常使用的两个接口,分别用于用户监听点击事件和长按事件,同样都是点击事件,Android工程师为什么不把这两个接口合并在一起而要分开呢?这里Android工程师就很好的遵循了接口隔离原则。虽然两个接口的功能类似,都是处理用户的点击事件,但试想一下,如果Android工程师把这两个接口合并到一起,每当我们要单独处理一个点击事件的时候,都必须连带把另外一个接口也要实现,这就会造成大量无用的实现,造成大量无用冗余代码。

  采用接口隔离原则对接口进行约束时,我们要让接口尽量小,但凡是都要有个度。细化的接口确实能极大的提高程序的灵活性,但过于细化接口,反而会造接口数量过多,反而使得程序难以维护,这就又背于我们的初衷了。至于这个度如何把握,需要我们在设计时,去反复推敲,反复思考,才能很好的践行这一职责。

五、迪米特原则:Law of Demeter(LOD)

      定义:最少知道原则,一个对象应该对其他对象保持最少的了解。简单点说,一个类应该对自己需要调用或者耦合的类知道的越少越好,类的内部如何实现于调用者或者依赖着没关系,调用者只需要知道他需要调用的方法即可。类与类之间的关系越密切,耦合度也就越大,当类发生改变时,对另外一个类的影响也就越大。迪米特原则还有一个更简单的定义:只与直接的朋友通信。首先来解释一下什么是直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。


六、开闭原则:Open Close Principle(OCP)

      定义:软件中的对象(类、模块、函数等)应该对于扩展是开放的,但是,对于修改是封闭的。在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会将错误引入原本已经经过测试的旧代码中,破坏原有系统。开闭原则是面向对象设计中最基础的设计原则,它指导我们如何建立稳定灵活的系统。开闭原则可能是设计模式六项原则中定义最模糊的一个了,它只告诉我们对扩展开放,对修改关闭,可是到底如何才能做到对扩展开放,对修改关闭,并没有明确的告诉我们。想起了刚毕业找工作的时候被难住的面试题。题目大概意思是这样。需要做一个解析网络数据的工具类,在服务端返回的数据能拿到数据格式(xml,json,或者其他),根据数据格式进行相应的解析。当时也天真,这算什么面试题,那么简单,用if else 判断格式,再进行数据解析,是xml,接按xml 解析, 是json,就按json解析。当时也没多想,大笔一挥,就这样写了。

当时写的代码大概是这样

    public void analysisData(Mode type){
        if(type = xml){
            //进行xml 数据格式解析
        }else if(type = json){
            // 进行 json 数据格式解析
        }
    }


结果,当然是被pass掉了。现在我们来看看我当时写的代码,感觉是解决的题目所提出的问题,但是如果后期来了一种新的数据格式,代码就会变成这样

    public void analysisData(Mode type){
        if(type = xml){
            //进行xml 数据格式解析
        }else if(type = json){
            // 进行 json 数据格式解析
        }else if(type = 流文件){
            // 进行 数据流解析
        }else if(...type.) {
            //  
        }
    }


每次新加一种数据格式,就需要修改源码。不仅繁琐,而且一不留神,改错了判断语句,加错了括号,以前的代码也会跟着出现问题。维护起来相当繁琐,如果后期有100中数据格式,意味着要写一百次 if else 判断。记得当时,面试官问了一句,你觉得你的代码,可以再怎么优化一下, 我天真的说了句,可以用switch语句替换if else 汗颜 - - 。

我们回到开闭模式,看下如何用开闭模式优化如上代码

public class HttpUtils {
    
    AnalysisDate analysisData;

    public void analysisData(Mode type){
        analysisDate.analysis(type);
    }
    
    public void setAnalysisData(AnalysisData analysisDate){
        this.analysisDate = analysisDate;
    }
    
}    

/**
 * 解析数据接口
 *
 */
public interface  AnalysisData{
    void analysis(Mode type);
}


public class JsonAnalysisDate implements AnalysisData{

    public void analysis(Mode type) {
        // json 数据解析
    }
}
public class XmlAnalysisDate implements AnalysisData{
    
    public void analysis(Mode type) {
        // xml 数据解析
    }
}


仔细观察上面优化之后代码,发现基本上前面所讲的五种模式都涉及在里面了。在仔细思考以及仔细阅读很多设计模式的文章后,终于对开闭原则有了一点认识。其实,我们遵循设计模式前面5大原则,以及使用23种设计模式的目的就是遵循开闭原则。也就是说,只要我们对前面5项原则遵守的好了,设计出的软件自然是符合开闭原则的,这个开闭原则更像是前面五项原则遵守程度的“平均得分”,前面5项原则遵守的好,平均分自然就高,说明软件设计开闭原则遵守的好;如果前面5项原则遵守的不好,则说明开闭原则遵守的不好。



你可能感兴趣的:(java,设计模式,android,面向对象,技巧)