编码灵魂(4)-依赖倒置原则

来源:互联网 发布:优化产业布局 编辑:程序博客网 时间:2024/05/19 17:24

引言

我觉得编码是有灵魂的,就像每个人都有信仰一样。那么如何去体现信仰,如何凸显灵魂就需要依赖它所固有的原则。最近学习了设计模式的六大原则,有所感悟,特此做总结和记录。在本文中我会详细介绍依赖倒置原则(DIP)的概念和含义,同时会给出几个例子详细解释为什么需要这个原则,希望对大家有所帮助。笔者目前整理的一些blog针对面试都是超高频出现的。大家可以点击链接:http://blog.csdn.net/u012403290

技术点
1、面对实现编程:
通俗来说就是,用继承普通类的方式来实现功能,不能很好体现出java的多态,同时具有很高的耦合性,于我们说的”高内聚低耦合”是不相符合的。

2、面对接口编程:
通俗来说就是,具体的实现是建立在接口类或者抽象类之上的。非常灵活,因为它可以产生很多个具体实现,耦合性很低,也是依赖倒置原则的核心思想。

依赖倒置原则:
以下是百度的解释:

依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。 -百度词条

或许大家看了之后不是很理解,其实依赖倒置的核心要求是要我们要面向接口编程,而不是面向实现编程。我把依赖倒置拆成两部分来解释。”依赖“,在我们的软件编程当中(面向实现编程),模块于模块之间存在着依赖,而且这种依赖理解上是:上层依赖下层,上层调用下层,抽象依赖于实现的。比如说你喜欢打篮球,那么你就是一个对象A,篮球就是一个对象B,那么就可以说你依赖于篮球。”倒置“,再面向实现的开发模式中,抽象是依赖于具体实现的,而倒置的含义就是说,①抽象不依赖于具体实现,而应该是实现依赖于抽象的,并且②高层也不应该依赖于底层,而应该依赖于抽象,因为它们的先后顺序和逻辑有了很大转变,所以说被倒置*了。比如说你就是一个对象A,你喜欢打篮球B,那么现在就需要引入一个接口I,你依赖这个接口,就是A依赖于I,同时篮球也依赖这个接口,就是B依赖于I,这就是依赖倒置原则。上述2点就是依赖倒置的核心含义。

一个反例

好了,介绍完依赖倒置,我们开始举例子说明为什么要遵循这个原则:比如说你喜欢打篮球,那么代码表示如下:

//篮球类package com.bw;public class Basketball {    public void play(){        System.out.println("玩篮球");    }}//你本身类package com.bw;public class You {    //你喜欢玩篮球    public void play(Basketball basketball){        basketball.play();    }}//运行测试类package com.bw;/** * @author brickworker * 关于类DIPTest的描述:依赖倒置原则的测试类 */public class DIPTest {    public static void main(String[] args) {        You you = new You();        Basketball basketball = new Basketball();        you.play(basketball);    }}//输出:玩篮球

上面的例子虽然简单,但是它没有遵循依赖倒置原则,它没有面向接口编程,如果项目越写越大,耦合度愈来愈高,后期维护就会显得非常困难。比如说,你不仅仅喜欢打篮球,你还喜欢踢足球。那要怎么实现呢?①你需要建立一个Football类,表示足球这个运动。②你需要去改动用户自身这个类(You类),使得它也支持踢足球。如果仅仅加一个运动也就算了,如果后面还有很多运动,你都喜欢怎么办?每次都要去修改用户自身这个类吗?是不是显得非常繁琐?但是如果这里运用了依赖倒置原则(面向接口编程),情况就不一样了,它需要修改原来的逻辑两步:①上层类不依赖下层类,直接依赖接口。②下层类(具体实现)也依赖接口,代码如下:

//定义一个接口,表示运动package com.bw;/** * @author brickworker * 关于类Sports的描述:运动类接口 */public interface Sports {//真正被依赖的对象    public void play();}//篮球类,实现sports接口,作为sports的具体实现package com.bw;public class Basketball implements Sports{//依赖抽象,具体实现    @Override    public void play() {        System.out.println("玩篮球");    }}//足球类,实现sports接口,作为sports的具体实现package com.bw;public class Football implements Sports{//依赖抽象,具体实现    @Override    public void play() {        System.out.println("踢足球");    }}//用户自身类:package com.bw;public class You {    //你喜欢玩篮球    public void play(Sports sports){//依赖抽象        sports.play();    }}//测试类:package com.bw;/** * @author brickworker * 关于类DIPTest的描述:依赖倒置原则的测试类 */public class DIPTest {    public static void main(String[] args) {        You you = new You();        Sports basketball = new Basketball();        Sports football = new Football();        you.play(basketball);        you.play(football);    }}//输出://玩篮球//踢足球

这样是不是就优雅了很多,而且类之间耦合度很低,如果后面你又喜欢了别的运动,只需要再去实现一次Sports接口就可以了。

仔细观察上面代码,看看于我前面说的两点修改规则是否相符呢?basketball实现了sports,就是底层依赖了抽象(football也是);再用户模块(You类)中,它的直接好友(在迪米特原则中说过)就是Sports,说明上层也是依赖了抽象。所以修改后的代码是符合依赖倒置原则的。

值得一提的是,有的小伙伴心里可能会想,为什么我是要玩篮球(basketball)的,你给我一个总的运动(sports)玩也玩得动?说明你没有看我“里氏替换原则“那篇文章,这里就体现了这个原则,不明白的,回去看看这篇博文。

好啦,今天的心得就写到这里,谢谢大家阅读,如果有各种问题和错误,千万拜托帮我指出,共同进步,谢谢各位。

0 0
原创粉丝点击