`
jiav_net
  • 浏览: 103625 次
文章分类
社区版块
存档分类
最新评论

组件设计原则之概念篇(二)

 
阅读更多

前三个组件设计原则关注组件的内聚,从本文开始,接下来将要介绍的三个原则更多关注组件间的耦合,其难度比前三个原则要大,我将结合一些示例进行讲解,主要参考资料仍然是Robert C.Martin的《敏捷软件开发:原则、模式与实践》(Agile Software Development: Principles, Patterns, and Practices)一书中的“Principles of Package and Component Design”一章。在讲解组件设计原则时,组件的涵义与包的涵义相似,都表示包含多个元素的组织结构。由于下面要介绍的无环依赖原则(ADP)稳定依赖原则(SDP)稳定抽象原则(SAP)相对较为复杂,因此,我决定分开进行讲解,尽量让每一个原则的讲解都能够全面而又深入,如有问题,欢迎大家多多与我交流!吐舌头

组件耦合性原则:稳定性 (Principles of Component Coupling: Stability)

无环依赖原则(The Acyclic Dependencies Principle, ADP)

Allow no cycles in the component dependency graph.
在组件的依赖关系图中不允许存在环。

环形依赖和无环依赖

ADP其实很容易理解,就是说在组件与组件之间不应该存在环形依赖关系。对于一些规模较大的项目,难免会包含多个组件,不同的组件可能会是由不同的开发团队所开发的,当一个组件发生改变时,所有依赖于它的其他组件也将需要重新集成和测试,如果在依赖关系中存在环,将导致循环依赖,使得一个组件修改之后的影响范围将变得非常大,致使该组件难以升级和重新发布。

首先我们来看一个无环依赖的例子,如图1所示。在图1中,组件Component3依赖于组件Component4和Component5,当需要修改Component3时,只需要重新链接Component4和Component5即可,对Component2没有任何影响;此外,修改Component4或Component5会导致Component3和Component1受到影响(沿着逆向的依赖关系即可寻找到所有受影响的组件),开发Component3和Component1这两个组件的开发人员可以决定是否需要和Component4或Component5的新版本集成以及何时集成。

图1 无环依赖示意图

如图1所示的依赖关系图是一个有向无环图 (Directed Acyclic Graph, DAG)。在发布整个系统时,可以按照自底向上的次序,首先编译、测试和发布Component4和Component5,然后是Component2和Component3,最后是Component1,这个开发和设计流程非常清晰,操作起来很容易。

如果我们设计不当,则会造成组件之间出现环形依赖,如图2所示:

图2 环形依赖示意图

图2所示的这种循环依赖将导致系统产生很多问题:在无环系统中,如果需要发布一个组件Component3的新版本,只需要重新链接Component4和Component5,因为Component4和Component5没有再依赖别的组件,所需时间和工作量都较小。但是在一个具有环形依赖的系统中,Component5又将依赖Component1,Component1依赖Component2,这导致整个系统所有组件全部需要重新编译和链接,使得Component3的发布变得非常麻烦,而且每一次发布的时候,重新构建(集成)整个系统所花费的成本将急剧升高,为了一个组件的发布就将做一次完整的构建,这会严重影响系统的开发进度,难过

此外,系统的集成和测试也变得越来越难以进行,难过,系统耦合度增加,修改和扩展都很麻烦,在有些更为复杂的项目中,如果存在大量的环形依赖,编译时间会随着模块数量成几何级数增长,毫无疑问,那绝对是无法忍受的!

而且在这种环形依赖系统中,组件的构建顺序也是一个很大的问题,由于组件之间存在循环依赖,那么哪一个组件应该第一个被构建呢?在编译一个组件时,它所依赖的组件从何而来,这居然变成了一个“先有鸡还是先有蛋”的问题,在有些编程语言中,此问题无解!快哭了

环形依赖的消除

Bob在ASD一书中提到了两种将组件间的环形依赖改造为DAG的方法,下面详细介绍一下这两种方法,里面也融合了我自己的一些见解,希望对大家有所帮助。

1. Apply the Dependency-Inversion Principle (DIP):应用依赖倒转原则

我就拿ASD书中的例子来说明一下如何实施,如图3所示:

图3 使用DIP消除依赖环

如图3所示,假设在某系统中,如果我们可以通过消除组件MyDialogs和MyApplication之间的依赖关系就可以消除环形依赖,通过分析,我们得知在组件MyDialogs中的类X依赖组件MyApplication中的类Y,此时,可以作出如下重构:

(1) 在组件MyDialogs中增加一个接口,如图3所示的X Server,类X依赖该接口;

(2) 将类Y作为接口X Server的实现类。

经过如上两步,依赖关系由MyDialogs依赖MyApplication变成了MyApplication依赖MyDialogs,编译次序为先编译MyDialogs,后续再编译MyApplication,由于X针对抽象的接口编程,使得系统的可扩展性变得更好。

此重构将组件之间的具体依赖关系转换为反向的抽象依赖关系,从而消除环形依赖。

除此之外,如果涉及到的类太多,不希望在原有组件中增加过多的接口,还可以增加一个新的组件,在这个新组件中包含一系列接口,原有组件针对这个包含多个接口的组件编程,如图4所示:

图4 增加抽象组件消除依赖环

在图4中,我们增加了一个新的抽象组件AbstractComponent,Component5不再直接依赖Component1,在AbstractComponent中包含了一组接口,这些接口的实现类在Component1中,Component5针对抽象接口编程,因此,Component5只需依赖AbstractComponent即可。此时,编译次序为:AbstractComponent --> Component5, Component4 --> Component3, Component2 --> Component1,可见,新的抽象组件的引入完全消除了环形依赖,而且由于AbstractComponent包含了大量的接口,让系统具有更好的可扩展性,如果提供一组新的实现AbstractComponent中接口的具体类,原有系统无须做太多的修改,符合开闭原则。

2. Create a new component that both of the components depend on:创建一个共同依赖的新组件

还是以图2为例,我们可以创建一个Component1和Component5都依赖的新组件,例如将原来Component1中Component5所依赖的那些类抽取出来,封装到新的组件,例如NewComponent中,此时,Component1和Component5都将依赖NewComponent,NewComponent也将成为第一个被编译的组件,如图5所示:

图5 增加新组件消除依赖环

在实际开发中,随着项目规模的扩大和应用程序的增加,组件之间的依赖关系会发生改变(组件中类之间的关系也会进一步清晰),我们需要随时对组件中的环形结构进行监控。如果出现了环形结构,就必须要使用某种方法来将其消除。这可能会需要创建一些新的组件,导致依赖链增长,依赖关系变得更加复杂,但为了消除依赖环,适当增加一些新的类或者新的组件是必须的,因为依赖环的存在是百害无一利,微笑

简而言之,ADP就是在组件的依赖关系图中不能存在环,如果存在,我们就应该想办法来消除环形依赖!

【作者:刘伟 http://blog.csdn.net/lovelion

分享到:
评论

相关推荐

    网络工程师考试考点分析与真题详解.网络设计与管理篇

    14 第2章 网络系统的设计 19 2.1 技术和产品的调研和评估 19 2.1.1 网络产品 19 2.1.2 网络技术 25 2.2 网络设计的目标和原则 26 2.2.1 网络设计目标 26 2.2.2 网络设计原则 27 2.2.3 网络...

    asp.net知识库

    ASP.NET 2.0使用Web Part创建应用程序之二(共二) 体验 .net2.0 的优雅(2) -- ASP.net 主题和皮肤 NET2.0系列介绍(一).NET 2.0 中Web 应用程序主题的切换 ASP.NET 2.0 中Web 应用程序主题的切换 2.0正式版中...

    网络工程师考试考点分析与真题详解.网络设计与管理篇.part4

    14 第2章 网络系统的设计 19 2.1 技术和产品的调研和评估 19 2.1.1 网络产品 19 2.1.2 网络技术 25 2.2 网络设计的目标和原则 26 2.2.1 网络设计目标 26 2.2.2 网络设计原则 27 2.2.3 网络...

    网络工程师考试考点分析与真题详解.网络设计与管理篇.part5

    14 第2章 网络系统的设计 19 2.1 技术和产品的调研和评估 19 2.1.1 网络产品 19 2.1.2 网络技术 25 2.2 网络设计的目标和原则 26 2.2.1 网络设计目标 26 2.2.2 网络设计原则 27 2.2.3 网络...

    网络工程师考试考点分析与真题详解.网络设计与管理篇.part2

    14 第2章 网络系统的设计 19 2.1 技术和产品的调研和评估 19 2.1.1 网络产品 19 2.1.2 网络技术 25 2.2 网络设计的目标和原则 26 2.2.1 网络设计目标 26 2.2.2 网络设计原则 27 2.2.3 网络...

    网络工程师考试考点分析与真题详解.网络设计与管理篇.part3

    14 第2章 网络系统的设计 19 2.1 技术和产品的调研和评估 19 2.1.1 网络产品 19 2.1.2 网络技术 25 2.2 网络设计的目标和原则 26 2.2.1 网络设计目标 26 2.2.2 网络设计原则 27 2.2.3 网络...

    网络工程师考试考点分析与真题详解.网络设计与管理篇.part6

    14 第2章 网络系统的设计 19 2.1 技术和产品的调研和评估 19 2.1.1 网络产品 19 2.1.2 网络技术 25 2.2 网络设计的目标和原则 26 2.2.1 网络设计目标 26 2.2.2 网络设计原则 27 2.2.3 网络...

    网络工程师考试考点分析与真题详解.网络设计与管理篇.part7

    14 第2章 网络系统的设计 19 2.1 技术和产品的调研和评估 19 2.1.1 网络产品 19 2.1.2 网络技术 25 2.2 网络设计的目标和原则 26 2.2.1 网络设计目标 26 2.2.2 网络设计原则 27 2.2.3 网络...

    MFC Windows程序设计(第2版修订版)--源代码

    本书的作者,jeff prosise,用其无与伦比的技巧向读者讲述了mfc程序设计中的基本概念和主要技术——再次阐释了在32位windows平台上进行了快速的面向对象开发的完美方法。  本书涵盖了以下专题:  事件驱动程序设计...

    软件工程完整ppt

     42软件设计的概念和原理  421模块和模块化  422抽象  423信息隐蔽和局部化  424模块独立性及其度量  43软件结构设计准则  44软件结构设计的图形工具  441软件结构图  442层次图  443HIPO图  45结构化...

    MFC Windows程序设计(第2版修订版)--详细书签版1卷

    本书的作者,jeff prosise,用其无与伦比的技巧向读者讲述了mfc程序设计中的基本概念和主要技术——再次阐释了在32位windows平台上进行了快速的面向对象开发的完美方法。  本书涵盖了以下专题:  事件驱动程序设计...

    MFC Windows程序设计(第2版修订版)--详细书签版2卷

    本书的作者,jeff prosise,用其无与伦比的技巧向读者讲述了mfc程序设计中的基本概念和主要技术——再次阐释了在32位windows平台上进行了快速的面向对象开发的完美方法。  本书涵盖了以下专题:  事件驱动程序设计...

    VB2008应用程序开发实例精讲(光盘文件)

     《VisualBasic2008应用程序开发实例精讲》语言简洁,内容丰富,结构合理,突出了应用性、实用性两个基本原则。不但详细介绍了VB 2008各种领域的应用开发技术,而且提供了相关理论知识、设计思路与实现方案,侧重于...

    ASP.NET3.5从入门到精通

    3.1.3 面向组件的概念 3.2 面向对象的C#实现 3.2.1 定义 3.2.2 创建一个类和其方法 3.2.3 类成员 3.2.4 构造函数和析构函数 3.3 对象的生命周期 3.3.1 类成员的访问 3.3.2 类的类型 3.3.3 .NET 的垃圾回收机制 3.4 ...

    亮剑.NET深入体验与实战精要2

    13.6 面向对象设计的原则 478 13.6.1 优先使用(对象)组合,而非(类)继承 478 13.6.2 针对接口编程,而非(接口的)实现 481 13.6.3 开放-封闭法则(OCP) 482 13.6.4 Liskov替换法则(LSP) 485 13.6.5 单一...

    亮剑.NET深入体验与实战精要3

    13.6 面向对象设计的原则 478 13.6.1 优先使用(对象)组合,而非(类)继承 478 13.6.2 针对接口编程,而非(接口的)实现 481 13.6.3 开放-封闭法则(OCP) 482 13.6.4 Liskov替换法则(LSP) 485 13.6.5 单一...

    精通Qt4编程(第二版)源代码

    \ 第4章 程序主窗口—— QMainWindow 卢传富 Qt应用程序的主窗口是由多个部件/组件构成的框架,本章通过一个简单文本编辑器的例子,介绍了主窗口的菜单、工具条、中心部件、锚接部件和状态条,并通过Qt设计器绘制和...

    ASP.NET 3.5 开发大全11-15

    3.1.3 面向组件的概念 3.2 面向对象的C#实现 3.2.1 定义 3.2.2 创建一个类和其方法 3.2.3 类成员 3.2.4 构造函数和析构函数 3.3 对象的生命周期 3.3.1 类成员的访问 3.3.2 类的类型 3.3.3 .NET的垃圾回收机制 3.4 ...

Global site tag (gtag.js) - Google Analytics