java 依赖倒置_java依赖的斗争:依赖倒置、控制反转和依赖注入

控制反转(Inversion Of Controller)的一个著名的同义原则是由Robert C.Martin提出的依赖倒置原则(Dependency Inversion Principle),它的另一个昵称是好莱坞原则(Hollywood Principle):不要找我们,让我们来找你。

依赖和耦合(Dependency and Coupling)

依赖:依赖描述了两个模型元素之间的关系,如果被依赖的模型元素发生变化就会影响到另一个模型元素。

简单的说,依赖就是一种需要。鱼需要水才能生存,鱼对水就有依赖关系;人需要进食才能活着,人对食物就有依赖关系。

耦合:如果改变程序的一个模块要求另一个模块同时发生变化,就认为这两个模块发生了耦合。

简单地说,耦合就是发生了依赖。和上面的例子一样,鱼和水之间发生了耦合,如果水发生了改变,会影响到鱼;人和食物之间发生了耦合,如果食物发生了改变,也会对人造成影响。

从上面的定义中可以看出,如果模块A调用模块B提供的方法,或者访问模块B中的某些数据成员(当然,在面向对象开发中一般不提倡这样做),我们就认为模块A依赖于模块B,模块A和模块B之间发生了耦合。

classA {

B b= new B(); //对B产生了依赖关系,即A和B发生了耦合关系

voiddoA() {

b.doB();

}

}classB {voiddoB() {//do something

}

}

那么,依赖对于我们来说到底是好事还是坏事呢?

由于人类的理解力有限,大多数人难以理解和把握过于复杂的系统(大神或天才除外),因此,把软件系统划分为多个模块,可以有效控制模块的复杂度,使每个模块都易于理解和维护。但在这种情况下,模块之间就必须以某种方式交换信息,也就是说,必然要发生某种耦合关系。如果某个模块和其它模块没有任何关联(哪怕是潜在的或隐含的依赖关系),我们就几乎可以断定,该模块不属于此软件系统,应该从系统中剔除。如果所有模块之间都没有任何耦合关系,其必然导致一个结果:整个软件不过是多个互不相干的系统的简单堆积,对每个系统而言,所有功能还是要在一个模块中实现,相当于没有做任何模块的分解。

因此,模块之间必然会有这样或那样的依赖关系,永远不要幻想消除所有依赖,但是,过强的耦合关系(如,一个模块的变化,会造成一个或多个其他模块也同时发生变化的依赖关系),会对软件系统的质量造成很大的危害。特别是当需求发生变化时,代码的维护成本将非常高。多以,我们必须想尽办法来控制和消除不必要的耦合,特别是那些会导致其它模块发生不可控变化的依赖关系。

依赖倒置、控制反转、依赖注入等原则,就是人们在和依赖关系进行艰苦斗争的过程中不断产生和发展起来的。

接口和实现分离(Interface And Implement)

把接口和实现分开是人们试图控制依赖关系的第一个尝试。

Java语言提供了纯粹的接口类(Interface),这种接口类不包含任何实现代码,只是定义了要做什么功能,具体的实现代码写在实现该接口类的实现类(Implement)中。调用者只需要关心接口能做什么功能,而不用关心功能具体是怎么实现的。

interface PayInterface { //定义接口

void payOnline(); //定义一个抽象方法

}class PayImplement implements PayInterface { //定义实现

void payOnline() { //实现该接口的抽象方法

alipay();

}voidalipay() {

System.out.println("使用支付宝支付");

}voidwechatPay() {

System.out.println("使用微信支付");

}

}

public classPayForEat {public static voidmain(String[] args) {

Pay pay= new payImplement(); //通过接口调用具体实现,实例化的是实现

pay.payOnline();

}|

通过定义接口,可以把A模块对B模块的调用,从对具体实现的依赖转向对抽象接口的依赖。在上述例子中,A模块可以理解成PayForEat,B模块可以理解成PayImplement,加入接口Pay,相当于在A模块和B模块之间添加了一个第三方桥梁C,A模块和B模块的依赖关联从直接关联变成了第三方关联,A通过C依赖于B,即A依赖于C,而C依赖于B。这样的话,当B模块发生改变,即上述例子中的支付方式发生改变(比如从使用支付宝支付改变成使用微信支付),A模块并不需要做任何改动去适应B模块的改动。

接口和实现分离可以很好地隔离各个模块,从而尽量降低各个模块之间的耦合,为系统提供更好的可扩展性和可维护性。

接口体现的是规范和实现分离的设计哲学,让软件系统的各个组件之间面向接口耦合,是一种松耦合的设计。

依赖倒置(Dependency Inversion Principle)

依赖倒置原则是建立在抽象接口的基础上:

A:上层模块不应该依赖于下层模块,它们共同依赖于一个抽象。

B:抽象不能依赖于具象,而是具象依赖于抽象。

含义是,为了消除两个模块间的依赖关系,应该在两个模块之间定义一个抽象接口,上层模块调用抽象接口定义函数,下层模块实现该接口。

interface PayInterface { //定义接口

void payOnline(); //定义一个抽象方法

}class PayImplement implements PayInterface { //定义实现

void payOnline() { //实现该接口的抽象方法//调用支付接口

}

}

这里定义了一个抽象的接口PayInterface,其中有一个抽象的payOnline()方法,具体的实现在PayImplement实现类中,实现了payOnline()方法。当调用方调用payOnline()方法的时候,由于多态性机制的作用,实际调用的是具体的PayImplement实现类中的实现。因此,抽象接口隔离了调用方和提供方中的具体实现类,使它们之间没有直接的耦合关系,可以独立地扩展或重用。

例如我们可以另外定义一个AliPayImplement实现或WepayImplement,应用程序既可以根据需要选择支付宝支付或微信支付,甚至可以支付宝付一半,微信付一半。由此可以总结出,这种通过抽象接口消除调用方和提供方的实现之间依赖关系的做法具有以下特点:

1.调用方调用提供方的抽象接口,依赖于提供方的抽象接口;具体的实现类派生自提供方的抽象接口,也依赖于提供方的抽象接口。

2.调用方和具体的提供方的实现完全独立,相互之间没有直接的依赖关系,只要保持接口类的稳定,调用方和提供方的具体实现都可以独立地发生改变。

3.提供方完全可以独立重用,调用方可以和任何一个实现了相同抽象接口的提供方协同工作。

一般情况下,由于提供方的设计者并不知道调用方会如何使用提供的功能,抽象接口大多由提供方设计者根据自己设想的典型使用模式总结出来,并保留一定的灵活度,以提供给调用方的开发者使用。

看到这里就明白,依赖倒置的意思,就是说要程序依赖于抽象接口,而不是依赖于具体实现,把对具体实现的依赖转移到了抽象接口。简单的说,就是要求对抽象编程,不要对实现编程,这样就降低了客户与实现模块间的耦合。

控制反转(Inversion Of Controller)

控制反转从字面上来看,就是对控制权的反转。把创建对象的控制权交给第三方容器,当程序中需要用到实例对象的时候,就向第三方容器发出请求,由第三方容器返回一个实例对象。

依赖注入(Dependency Injection)

依赖注入是控制反转的具体实现。意思就是说当程序中需要用到实例对象的时候,才去向第三方容器发出请求,由第三方容器返回实例对象(注入)。

"忙碌且感恩的人,不会缺爱。"

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1) 优秀的程序应该是这样的:阅读时,感觉很优雅;新增功能时,感觉很轻松;运行时,感觉很快速,这就需要设计模式支撑。2) 设计模式包含了大量的编程思想,讲授和真正掌握并不容易,网上的设计模式课程不少,大多讲解的比较晦涩,没有真实的应用场景和框架源码支撑,学习后,只知其形,不知其神。就会造成这样结果: 知道各种设计模式,但是不知道怎么使用到真实项目。本课程针对上述问题,有针对性的进行了升级 (1) 授课方式采用 图解+框架源码分析的方式,让课程生动有趣好理解 (2) 系统全面的讲解了设计模式,包括 设计模式七大原则、UML类图-类的六大关系、23种设计模式及其分类,比如 单例模式的8种实现方式、工厂模式的3种实现方式、适配器模式的3种实现、代理模式的3种方式、深拷贝等3) 如果你想写出规范、漂亮的程序,就花时间来学习下设计模式吧课程内容和目标本课程是使用Java来讲解设计模式,考虑到设计模式比较抽象,授课采用 图解+框架源码分析的方式1) 内容包括: 设计模式七大原则(单一职责、接口隔离、依赖、里氏替换、开闭原则、迪米特法则、合成复用)、UML类图(类的依赖、泛化和实现、类的关联、聚合和组合) 23种设计模式包括:创建型模式:单例模式(8种实现)、抽象工厂模式、原型模式、建造者模式、工厂模式。结构型模式:适配器模式(3种实现)、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式(3种实现)。行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)2) 学习目标:通过学习,学员能掌握主流设计模式,规范编程风格,提高优化程序结构和效率的能力。
依赖倒置(Dependency Inversion)和控制(Inversion of Control)都是软件设计模式中的重要概念。 依赖倒置(Dependency Inversion)是指高层模块不应该依赖于低层模块,而是应该依赖于抽象接口。这意味着在设计时,我们应该通过接口或抽象类来定义模块之间的依赖关系,而不是直接依赖于具体实现类。依赖倒置可以提高代码的灵活性和可维护性,使得模块之间的耦合度降低。 控制(Inversion of Control),简称IOC,是指控制流程的。传统的程序设计中,程序员负责控制对象的创建和生命周期,而在IOC中,这些控制权被给了容器或框架。它包括依赖注入(Dependency Injection)和依赖查找(Dependency Lookup)两种方式。 依赖注入(Dependency Injection)是指通过外部传递依赖对象的方式来实现对象之间的解耦。常见的方式有构造函数注入、属性注入和方法注入等。通过依赖注入,我们可以实现模块之间的松耦合,方便进行单元测试和代码重用。 依赖查找(Dependency Lookup)是指通过容器或框架提供的机制来查找和获取依赖对象。它与依赖注入相比,更加灵活,但也增加了代码的复杂性和对容器的依赖性。 综上所述,依赖倒置控制是设计模式中重要的概念,可以提高代码的可维护性和灵活性。依赖倒置通过抽象接口来定义模块之间的依赖关系,而控制则将对象的创建和生命周期的控制权交给了容器或框架。依赖注入依赖查找是实现控制的两种方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值