依赖和耦合关系

上传人:人*** 文档编号:469191717 上传时间:2023-12-25 格式:DOCX 页数:9 大小:339.13KB
返回 下载 相关 举报
依赖和耦合关系_第1页
第1页 / 共9页
依赖和耦合关系_第2页
第2页 / 共9页
依赖和耦合关系_第3页
第3页 / 共9页
依赖和耦合关系_第4页
第4页 / 共9页
依赖和耦合关系_第5页
第5页 / 共9页
点击查看更多>>
资源描述

《依赖和耦合关系》由会员分享,可在线阅读,更多相关《依赖和耦合关系(9页珍藏版)》请在金锄头文库上搜索。

1、依赖和耦合关系1、依赖和耦合(Dependency and Coupling)(1)什么是依赖Rose的帮助文档上是这样定义“依赖”关系的:“依赖描述了两个模型元素之间的关系,如果被依赖 的模型元素发生变化就会影响到另一个模型元素。典型的,在类图上,依赖关系表明客户类的操作会调用 服务器类的操作。”(2)什么是耦合Martin Fowler在Reducing Coupling一文中这样描述耦合:“如果改变程序的一个模块要求另一个 模块同时发生变化,就认为这两个模块发生了耦合。” Fowler 2001 注意:从上面的定义可以看出:如果模块A调用模块B提供的方法,或访问模块B中的某些数据成员(当

2、 然,在面向对象开发中一般不提倡这样做),我们就认为模块A依赖于模块B,模块A和模块B之间发生 了耦合。耦合是依赖的同义词,被定义为“两个元素之间的一种关系,其中一个元素变化,导致另一个元素变 化”。抽象耦合被定义为“若类A维护一个指向抽象类B的引用,则称类A抽象耦合于B”。2、依赖是不可避免的(1)“分而治之”的问题处理方法对于复杂的系统,我们常常采用它划分成多个模块,这样将能够有效地控制模块的复杂度,使每个模 块都易于理解和维护。(2)“分而治之”的结果是产生依赖关系 一旦我们采用“分而治之”的处理方法后,模块之间就必须以某种方式交换信息,也就是必然要 发生某种耦合关系。 如果某个模块和其

3、它模块没有任何关联(哪怕只是潜在的或隐含的依赖关系),我们就几乎可以 断定,该模块不属于此软件系统,应该从系统中剔除。 如果所有模块之间都没有任何耦合关系,其结果必然是:整个软件不过是多个互不相干的系统的 简单堆积,对每个系统而言,所有功能还是要在一个模块中实现,这等于没有做任何模块的分解。(3)依赖是不可避免的因此,模块之间必定会有这样或那样的依赖关系,我们永远也不要幻想消除所有的依赖(耦合关系)。 我们在类的设计时,应该首先考虑的是该类应该尽可能依赖不经常变化的“目标”-比如,系统的API 库或者框架中的组件-试图令具体的、易变的模块依赖于抽象的、稳定的模块的基本原则。在Java中,表示字

4、符串的是具体内String0该类是稳定的,也就是说,它不太会改变。因此,直接依 赖于它不会造成损害。既然变化不可避免,我们所能做的就是处理好依赖关系,将变化造成的影响的波及范围尽量减小。(4)我们所追求的是尽可能降低过强的耦合关系“依赖”是和“变化”紧密联系在一起的概念。由于依赖关系的存在,变化在某处发生时,影响会波 及开去,造成很多修改工作,这就是依赖的危害。 因为,过强的耦合关系(如一个模块的变化会造成一个或多个其他模块也同时发生变化的依赖关 系)会对软件系统的质量造成很大的危害。 特别是当需求发生变化时,代码的维护成本将非常高。所以,我们必须想尽办法来控制和消解不 必要的耦合,特别是那种

5、会导致其它模块发生不可控变化的依赖关系。(5)如何达到-采用什么的策略或者方法依赖倒置、控制反转、依赖注入等原则。3、依赖倒置(DIP-Dependency Inversion Principle)(1)什么是依赖倒置-将依赖关系倒置为依赖接口依赖倒置原则就是建立在抽象接口的基础上的。Robert Martin这样描述依赖倒置原则Martin 1996: 上层模块不应该依赖于下层模块,它们共同依赖于一个抽象。抽象不能依赖于具体,具体依赖于抽象-也就是“系统的核心逻辑”不依赖于“具体的实现细节”。依赖性倒置原则形式化了抽象耦合的概念,明确表述了应该“依赖于抽象类,不要依赖于具体类”。(2)如何达

6、到依赖倒置的效果为了消解两个模块间的依赖关系,应该在两个模块之间定义一个抽象接口,上层模块调用抽象接口定 义的方法,下层模块实现该接口。针对接口编程遵守上述原则,从而在很大程度上阻止了变化波及范围的扩大,有效地隔离了变化,有 助于增强系统的可重用性和可扩展性。(3)为什么要依赖接口 因为抽象是相对稳定的或者是相对变化不频繁的,而具体是易变的因此,要使我们的设计具有很大的灵活性,就需要做到大家都依赖于抽象的东西,而利用抽象隔离具 体类之间的关系,这样使得“具体”的任何改动都可以在局部范围内实现,而不影响其它的结构。比如,一个IO系统它必然就有READ/WRITE这两个抽象,至于具体是磁盘还是键盘

7、,那是下面的实 现不同了,通过这种构架,能保持软件的弹性与可维护性。 依赖抽象是我们实现代码扩展和运行期内绑定(多态)的基础因为一旦类的使用者依赖某个具体的类,那么对该依赖的扩展就无从谈起;而依赖某个抽象类,则只 要实现了该抽象类的子类,都可以被类的使用者使用,从而实现了系统的扩展。(4)示例(摘录网上资料)这里举个比较好笑的例子:一个即将做领导的儿子问曾经做领导的父亲怎么才能平步青云,父亲说你 不能说假话,因为老百姓会不答应,也不能说实话,因为领导会对你有意见,儿子思索良久问:那我该说 什么?父亲意味深长的说:空话笑话不但好笑,还能反映一定的道理,为啥空话这么有用,因为他是抽象的,而抽象不涉

8、及到一些具 体的数据或者事务,因此他是稳定的,是不容易变化的,同时基本上也是正确的。4、依据“依赖倒置原则”进行编程开发(1)体现倒置原则的UML类图以前传统的过程设计中是从上到下的一条依赖线(2)其主要的优点 由于在依赖倒置中,通过抽象接口达到隔离了 “服务的提供者”和“服务的请求者”,使它们之 间没有直接的耦合关系,两者可以独立地扩展或重用。 依赖倒置原则是许多面向对象技术的优点的根本。合理地应用它对于建立可复用的框架是必要 的。对于构建富有变化弹力的代码也是相当重要的。而且,由于抽象和具体相互完全分离,代码 的维护就容易很多了。依赖倒置原则一般应用于类与类之间的代码级的依赖关系。(3)应

9、用依赖倒置原则的代码示例 任何实例对象变量都不应该持有一个指向具体类的引用,而应该为接口类型的对象声明class SomeClass (private Somelnterface obj=null; 任何类都不应该从具体类派生,而应该实现某个接口-面向接口编程,而不要面向实现编程class SomeClass implements Somelnterface / extends SuperClass5、依赖倒置原则示例(1)持久层中的各个组件常规的设计和实现方案在很多Web应用系统中,都需要对后台的数据库系统进行访问以实现数据存储的目的。而一个常见的 解决手段是使用分层的设计思想和方法,将We

10、b应用系统中的持久层中的各个组件分为数据访问操作组件 (DAO, Data Access Object)和数据连接组件,下面的图中所示为这种常规的设计和实现方案的类图。(2)常规设计和实现方案中所反映出的问题从上面的图中的所示的数据访问操作组件和数据连接组件之间的关系来看,两者产生了紧密的藕合关 系。一旦数据连接组件有了任何变化,数据访问操作组件都有可能会受其影响而需要被改动。当然,如果只是针对这两个类本身而言的话,这种依赖关系根本算不上什么问题。然而,在一个实际 的应用系统中,数据访问操作组件和数据连接组件都会由不只一个类而构成的,并都有一定的技术实现上 的复杂度,这时它们两者之间的这种依赖

11、关系就会增加系统的复杂性;而且随着应用系统中的各个程序模 块越来越多、功能实现也越来越复杂时,这种由于两者之间的紧密藕合所带来的系统的复杂度会越来越高。 因此,如果不限制它们之间的紧密藕合联系,那模块间的依赖、程序的复杂度和开发维护的难度都会成指 数上升。(3)对设计进行优化一一在两者之间添加一个抽象的接口在两者之间添加一个数据连接组件的接口,并在其中包含数据访问操作组件中所需要的各种数据连接 的服务方法的定义,而某个具体的数据连接组件则实现这个接口。此时数据访问操作组件则只需要调用数 据连接组件接口中的服务来实现数据库的各种连接功能,两者都只依赖于数据连接组件的接口。请见下面 的图中所示的优

12、化设计结果的类图。这样,数据访问操作组件到数据连接组件的依赖关系被数据连接组件的接口所隔离开。因为在接口中 只包含了所需要的各种连接的服务功能的定义,而不包括任何连接的服务功能的具体实现,所以数据连接 组件的接口的内容在具体设计时也会很简单。在数据连接组件接口不变的情况下,数据访问操作组件和某 个具体的数据连接组件这两个模块都可以自由地进行修改而不影响到对方(比如添加另一个数据连接组 件),依赖关系也变得简单和可管理。(4)进一步改进本设计和实现方案一一核心逻辑不依赖于具体的实现细节如果从系统架构的角度来看上面的图中所示的设计和实现方案还存在一定的问题,因为数据访问操作 组件所提供的功能是整个

13、应用系统的数据访问的核心部分,而数据连接组件中的各个功能方法则可以看成 是具体实现的的细节。因此,从这个角度来看图中优化设计后的结果时,该设计是“核心逻辑依赖于具体 的实现细节”。当然,也就没有遵守依赖倒置原则中的“抽象不能依赖于具体,具体依赖于抽象”的要求。因为,当细节变化(数据连接中的数据源或者连接方式发生变化)时,数据访问操作组件中的核心逻 辑(数据访问的实现逻辑)也会受到一定的影响。因为当应用系统中的数据存储从某一种形式的数据库系 统改变另一种形式的数据库系统(比如从微软的MS SQLServer2000改变为Oracle10G数据库系统)时, 此时也将必然会影响到数据访问操作组件中有

14、关的的具体实现方法(因为对这两种不同的数据库系统在具 体进行数据访问操作实现时的SQL语句或者涉及对存储过程的调用时,是不一样的!)。为了能够达到当系统中的数据库类型发生变化时,不至于影响到对数据库访问组件的使用者(业务层 组件)的代码,有必要对系统设计进一步完善!下面的图所示为这样的应用场景下的各个类的设计要求的 图示。(5)利用数据库访问操作的抽象接口进行隔离因此,有必要对上面的图中所体现出的设计结果进一步地改进和完善。主要的思路是将由于数据库连 接方式的不同而造成的数据库访问操作的不同隔离开,在数据库访问操作这一层次同样也设计出一个数据 库访问操作的抽象接口,并为该数据库访问操作的抽象接

15、口提供不同的具体数据库访问操作的实现类。这样的设计能够避免改动对数据库访问操作的使用类(一般为上层的业务层组件类)的代码,下面的 图为进一步完善后的设计结果的类图。控制反转(loc-Inversion of Control)1、消解框架和我们的应用系统类之间的依赖关系前面依赖倒置原则描述的是类与类之间的代码级的依赖关系。如果我们开发的系统是基于某种框架系 统来开发的,此时我们的类对目标框架的依赖关系就会更强烈一点。那么,该如何消解框架和我们的应用 系统类之间的依赖关系呢?利用控制反转。2、控制反转(1)什么是控制反转“好莱坞原则(不要调用我们,让我们调用你)”。(2)面向框架和面向系统类库开发的不同点 框架和类库最重要的区别是:框架是一个半成品的应用程序,而类库只包含一系列可被应用 程序调用的类。 类库给用户提供了一系列可复用的类,这些类的设计都符合面向对象原则和模式。用户使用时, 可以创建这些类的实例,或从这些类中继承出新的派生类,然后调用类中相应的功能。在这一过 程中,类库总是被动地响应用户的调用请求。 框架则会为某一特定目的实现一个基本的、可执行的架构。框架中已经包含了应用程序从启动到 运行的主要流程,流程中那些无法预先确定的步骤留给用户来实现。程序

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 学术论文 > 其它学术论文

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号