耦合度的概念html
耦合度是对模块(类)间关联程度的度量,能够用"联系"做同义词,"独立性"做反义词。java
耦合度分类(由高到低)ajax
(1)内容耦合。当一个模块直接修改或操做另外一个模块的数据,或者直接转入另外一个模块时,就发生了内容耦合。此时,被修改的模块彻底依赖于修改它的模块。类与类之间直接调用或继承关系都是属于这种耦合。spring
需彻底避免内容耦合,重点在于不要在类内部直接操做另外一个类的对象的数据成员,能够经过在操做类中增长一个函数接口向客户类提供服务来实现数据库
(2)公共耦合。两个及两个以上的模块共同引用一个全局数据项就称为公共耦合。数据结构
(3)控制耦合。一个模块在界面上传递一个信号(如开关值、标志量等)控制另外一个模块,接收信号的模块的动做根据信号值进行调整,称为控制耦合。框架
(4)标记耦合。模块间经过参数传递复杂的内部数据结构,称为标记耦合。此数据结构的变化将使相关的模块发生变化。函数
(5)数据耦合。模块间经过参数传递基本类型的数据,称为数据耦合。优化
(6)非直接耦合。模块间没有信息传递时,属于非直接耦合。
spa
1. 低耦合(Low Coupling)
“低耦合”这个词相信你们已经耳熟能详,咱们在看spring的书籍、MVC的数据、设计模 式的书籍,无处不提到“低耦合、高内聚”,它已经成为软件设计质量的标准之一。那么什么是低耦合?耦合就是对某元素与其它元素之间的链接、感知和依赖的量 度。这里所说的元素,便可以是功能、对象(类),也能够指系统、子系统、模块。假如一个元素A去链接元素B,或者经过本身的方法能够感知B,或者当B不存 在的时候就不能正常工做,那么就说元素A与元素B耦合。耦合带来的问题是,当元素B发生变动或不存在时,都将影响元素A的正常工做,影响系统的可维护性和 易变动性。同时元素A只能工做于元素B存在的环境中,这也下降了元素A的可复用性。正由于耦合的种种弊端,咱们在软件设计的时候努力追求“低耦合”。低耦 合就是要求在咱们的软件系统中,某元素不要过分依赖于其它元素。请注意这里的“过分”二字。系统中低耦合不能过分,好比说咱们设计一个类能够不与JDK耦 合,这可能吗?除非你不是设计的Java程序。再好比我设计了一个类,它不与个人系统中的任何类发生耦合。若是有这样一个类,那么它必然是低内聚(关于内 聚的问题我随后讨论)。耦合与内聚经常是一个矛盾的两个方面。最佳的方案就是寻找一个合适的中间点。
哪些是耦合呢?
1.元素B是元素A的属性,或者元素A引用了元素B的实例(这包括元素A调用的某个方法,其参数中包含元素B)。
2.元素A调用了元素B的方法。
3.元素A直接或间接成为元素B的子类。
4.元素A是接口B的实现。
幸运的是,目前已经有大量的框架帮助咱们下降咱们系统的耦合度。好比,使用struts咱们 能够应用MVC模型,使页面展示与业务逻辑分离,作到了页面展示与业务逻辑的低耦合。当咱们的页面展示须要变动时,咱们只须要修改咱们的页面,而不影响我 们的业务逻辑;一样,咱们的业务逻辑须要变动的时候,咱们只须要修改咱们的java程序,与咱们的页面无关。使用spring咱们运用IoC(反向控 制),下降了业务逻辑中各个类的相互依赖。假如类A由于须要功能F而调用类B,在一般的状况下类A须要引用类B,于是类A就依赖于类B了,也就是说当类B 不存在的时候类A就没法使用了。使用了IoC,类A调用的仅仅是实现了功能F的接口的某个类,这个类多是类B,也多是另外一个类C,由spring的配 置文件来决定。这样,类A就再也不依赖于类B了,耦合度下降,重用性提升了。使用hibernate则是使咱们的业务逻辑与数据持久化分离,也就是与将数据 存储到数据库的操做分离。咱们在业务逻辑中只须要将数据放到值对象中,而后交给hibernate,或者从hibernate那里获得值对象。至于用 Oracle、MySQL仍是SQL Server,如何执行的操做,与我无关。
可是,做为优秀的开发人员,仅仅依靠框架提供的下降软件耦合的方法是远远不够的。根据个人经验,如下一些问题咱们应当引发注意:
1) 根据可能的变化设计软件
咱们采用职责驱动设计,设计中尽力作到“低耦合、高内聚”的一个很是重要的前提是,咱们的软 件是在不断变化的。若是没有变化咱们固然就不用这么费劲了;可是若是有变化,咱们但愿经过以上的设计,使咱们在适应或者更改这样的变化的时候,付出更小的 代价。这里提供了一个很是重要的信息是,咱们努力下降耦合的是那些可能发生变动的地方,由于下降耦合是有代价的,是以增长资源耗费和代码复杂度为代价的。 若是系统中某些元素不太可能变动,或者下降耦合所付出的代价太大,咱们固然就应当选择耦合。有一次我试图将个人表现层不依赖于struts,但发现这样的 尝试代价太大而失去意义了。对于软件可能变动的部分,咱们应当努力去下降耦合,这就给咱们提出一个要求是,在软件设计的时候能够预判往后的变化。根据以往 的经验我认为,一个软件的业务逻辑和采用的技术框架每每是容易变化的2个方面。客户需求变动是咱们软件设计必须考虑的问题。在RUP的开发过程当中,为何 须要将分析设计的过程分为分析模型和设计模型,愚觉得,从分析模型到设计模型的过程其实是系统从知足直接的客户需求到优化系统结构、适应可预见的客户需 求变动的一个过程。这种客户需求的变动不只仅指对一个客户需求的变动,更是指咱们的软件从适应一个客户需求到适应更多客户需求的过程。另外一个方面,如今技 术变动之快,EJB、hibernate、spring、ajax,一个一个的技术像走马灯同样从咱们脑海中滑过,咱们真不知道明天我在用什么。在这样的 状况下,适应变化就是咱们最佳的选择。
2) 合理的职责划分
合理的职责划分,让系统中的对象各司其职,不只是提升内聚的要求,同时也能够有效地下降耦 合。好比评审计划BUS、评审表BUS、评审报告BUS都须要经过评审计划DAO去查询一些评审计划的数据,若是它们都去直接调用评审计划DAO(如图 A),则评审计划BUS、评审表BUS、评审报告BUS三个对象都与评审计划DAO耦合,评审计划DAO一旦变动将与这三个对象都有关。在这个实例中,实 际上评审计划BUS是信息专家(关于信息专家模式我将在后面讨论),评审表BUS和评审报告BUS若是须要得到评审计划的数据,应当向评审计划BUS提出 需求,由评审计划BUS提供数据(如图B)。通过这样的调整,系统的耦合度就下降了。
3) 使用接口而不是继承
经过对耦合的分析,咱们不难发现,继承就是一种耦合。若是子类A继承了父类B,不管是直接或 间接的继承,子类A都必将依赖父类B。子类A必须使用在存在父类B的环境中,父类B不存在子类A就不能使用,这样将影响子类A的可移植性。一旦父类B发生 任何变动,更改或去掉一个函数名,或者改变一个函数的参数,都将致使子类A不得不变动,甚至重写。假如父类B的子类数十上百个,甚至贯穿这个项目各个模 块,这样的变动是灾难性的。这种状况最典型的例子是咱们如今使用hibernate和spring设计DAO对象的方式,具体的描述参见我写的《如何在 struts + spring + hibernate的框架下构建低耦合高内聚的软件结构》一文。