四、接口隔离原则: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 数据格式解析 } }
public void analysisData(Mode type){ if(type = xml){ //进行xml 数据格式解析 }else if(type = json){ // 进行 json 数据格式解析 }else if(type = 流文件){ // 进行 数据流解析 }else if(...type.) { // } }
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项原则遵守的不好,则说明开闭原则遵守的不好。