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

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

 
阅读更多

最后两个组件设计原则将会结合软件度量来进行介绍,将引入一些软件度量因子,对组件设计进行定量的分析与研究。

稳定依赖原则(The Stable-Dependencies Principle, SDP)

Depend in the direction of stability.
朝着稳定的方向进行依赖。

稳定性与依赖性

随着需求的明确和系统的演化,组件不可能一成不变,必要的修改是肯定的。根据前面所介绍的共同封闭原则(CCP),我们需要创建一些对某一(某些)类型的变化敏感的组件,这些组件应该是可以变化的,而且有时候我们需要它改变。由于组件之间存在依赖关系,可能会导致某些本来很容易修改的组件因为依赖它的组件而变得难以修改,SDP原则正是从这个角度出发,用于保证那些原本易于更改的组件不会被那些比它们更难更改的组件所依赖在Robert C. Martin的ASD一书中,使用定量的方法来研究如何设计组件之间的依赖关系,在此,Sunny对该方法本身不加以太多评论,先介绍下Bob大叔到底是如何定义和实施SDP的,还是挺有意思的。微笑

在讲解组件稳定性之前,我想先介绍一下组件之间依赖性产生的原因。众所周知,在一个系统中肯定会包含多个类,无论我们如何来组织类,降低组件之间的耦合度,不同组件中的类之间难免还是存在一些关系,例如关联、继承(实现)或依赖关系等,在组件层次,我们可以认为两个组件中的类之间如果存在关联、继承、依赖等关系,那么这两个组件之间就存在依赖关系,将组件之间的各种关系统一称为依赖关系。

接下来再介绍组件的稳定性,何谓稳定性,根据韦氏词典的定义,稳定性是指某物品“不容易被移动”。在软件中,组件的稳定性是指改变它的难易程度要想提高一个组件的稳定性,使得它难以修改,一个最常用的方法是让更多其它的组件依赖它。依赖一个组件的其他组件越多,它的修改所造成的影响也就越大,修改所带来的工作量也越大,我们认为它就越稳定(如果这个设计方案出自一个菜鸟之手,另当别论,大笑,可能会因为一些不必要的依赖导致系统的耦合度增加,让系统难以扩展和维护。此处所涉及的一些依赖都是必须的,不存在设计上的缺陷和失误)。

如图1所示,组件X被组件L、M和N所依赖,因此,我们至少有三个合理的理由来不对X进行修改,可以称组件X对组件L、M和N负责。此外,X并没有依赖任何其他组件,因此,外部环境的影响对X而言不会产生任何改变,此时可以称X是无依赖性的

图1 X是一个无依赖性的稳定的组件

在图2中,组件Y依赖组件L、M和N,它是一个很不稳定的组件,没有任何组件依赖Y,因此它不承担任何责任。此外,Y依赖三个外部组件,L、M和N的修改都将对Y造成影响,此时可以称Y是有依赖性的

图2 Y是一个有依赖性的不稳定的组件

为了能够对组件的稳定性进行量化,Bob引入了几个数值来计算组件的位置稳定性(Positional Stability)

稳定性度量 (Stability Metrics)

为了度量组件的稳定性,引入了如下几个度量因子:

(1) Ca (afferent couplings):输入耦合度,是指位于一个组件外部,需要依赖于组件中的类的其他类的数量(The number of classes outside this component that depend on classes within this component.)。在图1中,组件X的输入耦合度为3,在图2中,组件Y的输入耦合度为0。

(2) Ce (efferent couplings):输出耦合度,是指位于一个组件内部,需要依赖组件外的其他类的类的数量(The number of classes inside this component that depend on classes outside this component.)。在图1中,组件X的输出耦合度为0,在图2中,组件Y的输出耦合度至少为1(Y中至少有一个类依赖外部类,也可能有多个类,而且可能不止3个类)。

(3) I (Instability):不稳定性因子,计算公式如下:

不稳定性因子I的取值范围为:[0,1]。I = 0表示一个组件具有最大的稳定性,不稳定性为0,也就是说Ce等于0,即输出耦合度为0,只存在别的组件依赖它,它不依赖别的组件,如图1中的组件X;I = 1表示一个组件具有最大的不稳定性,也就是Ca等于0,即输入耦合度为0,没有组件依赖它,它却依赖别的组件,如图2中的组件Y。通过计算和一个组件内的类具有依赖关系的组件外类的个数,就可以计算出Ca和Ce。

下面通过一个示例来进一步说明这些度量值的计算,本示例来自ASD一书:

图3 组件依赖关系示例

在图3中,组件Pc外部有3个类(Pa两个,Pb一个)依赖于Pc中的类,因此,Ca = 3,此外,Pc中有一个类u依赖外部组件Pd,因此,Ce = 1,I = Ce / (Ca + Ce) = 1/4。

在C++中,依赖关系通常会通过#include语句来体现,在Java中,通常通过import语句以及类的修饰名称(包含包名的完整名称)来体现,在C#中,通常通过using语句来体现。如果在源代码中每一个文件中只有一个类,那么计算I就非常简单了,我正准备做一个小工具来自动计算这些度量因子,微笑

SDP规定一个组件的I度量值应该大于它所依赖的组件的I度量值,也就是说,I度量值应该顺着依赖的方向减小

当一个组件的I值为1时,说明没有任何其他组件依赖它(Ca = 0),而它却依赖其他组件(Ce > 0),这是一个最不稳定的状态。由于没有组件依赖它,因此它就没有不发生改变的理由,而它所依赖的组件会给它提供大量的更改理由。当一个组件的I值为0时,说明其他组件会依赖于该组件(Ca > 0),但是该组件却不依赖其他任何组件(Ce = 0)。这种组件达到最大程度的稳定性,由于它的依赖者的存在,导致它本身难以改变,拥有不去发生改变的理由,而且依赖这个组件的其他组件越多,不去修改该组件的理由也就越多,改变带来的影响也越大。

简单来说,SDP要求我们将I值小的组件放在底层,将I值大的组件放在顶层,因为I值越小意味着依赖它的外部组件越多,它的改变所带来的影响越大,越底层的模块应该越稳定,因此,不稳定因子I应该越小。沿着依赖链,I值应该逐步减小。

可变的组件稳定性

组件的稳定性并不是不能发生变化的,如果我们发现一个系统的组件设计违反了SDP,也就是依赖链并不是按照I值递减的次序构建的,我们可以需要对组件之间的依赖关系进行调整,使系统尽量满足SDP。可改变的组件位于顶部并且依赖于底部那些稳定的组件(The changeable components are on top and depend on the stable component at the bottom.)

下面通过一个实例来讲解如何通过调整组件之间的依赖关系,使之满足SDP。

图4 某系统组件依赖关系示例

在图4中,组件ComponentA和ComponentB的I值为1,ComponentC的I值为1/3,ComponentD的I值为2/3,ComponentE和ComponentF的I值为0,由此可见,ComponentC和ComponentD之间的依赖关系违反了SDP。

问题来了,如何改进,使之满足SDP?疑问

通过分析,我们发现,ComponentC与ComponentD之间的依赖关系是因为ComponentC中的类X依赖ComponentD中的类Y,如何消除这两个类之间的依赖关系成为关键所在?

解决方法很简单,与之前的ADP一样,通过依赖倒转原则DIP来实现,具体做法如下:

(1) 提供一个Y的抽象类IY,并引入一个新的组件AbstractComponent,将IY增加到AbstractComponent中;

(2) 类X依赖于AbstractComponent中的抽象类IY,而不再直接依赖于Y,将Y作为IY的子类,因此ComponentC将依赖于AbstractComponent,ComponentD也将依赖于AbstractComponent。

重构之后的组件结构如图5所示:

图5 重构之后的组件结构

看到这里,大家是不是觉得这个结构似曾相识,很多系统的架构与图5非常相似,是的,这就是我们常常会使用的引入抽象层的分层结构,不过在此我将每一层都封装在一个组件中。这个结构是严格满足SDP的,无论哪一条依赖链都是按照I值递减的次序来设计的。

事实上,我们在做构件的架构设计时,不应该经常改变的组件通常代表着系统的高层架构和设计决策,应该是稳定的,需要把这些与系统的高层设计有关的类放进稳定的组件中(如I值为0的组件),不稳定的组件(如I值为1的组件)中应该只包含那些很可能会发生改变的类。

但是,如果我们把高层设计放进这些稳定的组件,那么会导致高层设计的源代码难以修改,将使得设计失去灵活性。如何让一个稳定性高的组件(I = 0)具有足够的灵活性,能够适应需求的变化,并能够满足开闭原则OCP呢?答案是:抽象的组件,包含抽象类(接口)的组件。SDP实际上就是组件设计中的OCP和DIP,稳定的组件通常会是一些抽象组件,这也对设计抽象组件的架构师和设计师提出了更高的要求。

简言之,从实施的角度来看,SDP要求我们合理地引入一些抽象组件,从而保证系统的稳定性和灵活性,使得系统能够符合SDP,更根本的目标还是符合OCP微笑

本文可能会有点太过理论,而且很多朋友可能平时很少接触软件度量方面的东东,不过看一看对研究和深入理解组件设计应该还是会有所帮助的,呵呵!奋斗

除了本文所提到的Bob大叔所引入的稳定性度量方法以外,不知道大家在日常工作中是否还有用一些其他衡量组件稳定性和易变性的方法?欢迎大家与我交流和讨论,吐舌头

【作者:刘伟 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组件设计]一书第三章关于ASP.NET运行原理讲述的补白 asp.net 运行机制初探(httpModule加载) 利用反射来查看对象中的私有变量 关于反射中创建类型实例的两种方法 ASP.Net应用程序的多进程模型 NET委托...

    网络工程师考试考点分析与真题详解.网络设计与管理篇.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 网络...

    软件工程完整ppt

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

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

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

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

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

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

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

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

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

    ASP.NET3.5从入门到精通

    第三篇 数据操作篇 第 7 章数据库与 ADO.NET 基础 7.1 数据库基础 7.1.1 结构化查询语言 7.1.2 表和视图 7.1.3 存储过程和触发器 7.2 使用SQL Server 2005 管理数据库 7.2.1 初步认识SQL Server 2005 7.2.2 创建...

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

    本书集实用性、思想性、趣味性于一体,内容共分为技术基础总结、系统架构设计思想及项目实战解析三部分,随书所附光盘收录大量实例代码及独家披露的商业系统,供读者参考学习。 本书适合于.NET初、中级开发人员参考...

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

    本书集实用性、思想性、趣味性于一体,内容共分为技术基础总结、系统架构设计思想及项目实战解析三部分,随书所附光盘收录大量实例代码及独家披露的商业系统,供读者参考学习。 本书适合于.NET初、中级开发人员参考...

    ASP.NET 3.5 开发大全11-15

    第三篇 数据操作篇 第7章 数据库与ADO.NET基础 7.1 数据库基础 7.1.1 结构化查询语言 7.1.2 表和视图 7.1.3 存储过程和触发器 7.2 使用SQL Server 2005 管理数据库 7.2.1 初步认识SQL Server 2005 7.2.2 创建数据库 ...

    ASP.NET 3.5 开发大全

    第三篇 数据操作篇 第7章 数据库与ADO.NET基础 7.1 数据库基础 7.1.1 结构化查询语言 7.1.2 表和视图 7.1.3 存储过程和触发器 7.2 使用SQL Server 2005 管理数据库 7.2.1 初步认识SQL Server 2005 7.2.2 创建数据库 ...

Global site tag (gtag.js) - Google Analytics