12

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

 3 years ago
source link: https://blog.csdn.net/LoveLion/article/details/8539543
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

      稳定抽象原则SAP是六个组件设计原则中的最后一个,它通常与稳定依赖原则SDP结合在一起,用于创建具有较高质量的组件依赖结构。终于是最后一个了,吐舌头

稳定抽象原则(The Stable-Abstractions Principle, SAP)

A component should be as abstract as it is stable.
组件的抽象程度应该与其稳定程度一致。

       SAP将组件的稳定性和抽象性联系了起来。SAP原则规定,一个稳定的组件应该是抽象的,这样在具备稳定性的同时也将具备较好的可扩展性。此外,它还规定,一个不稳定的组件应该是具体的,它的不稳定性要求其内部的具体代码应该是易于修改的,这种修改不会给其他组件带来太大的影响。

       在一个相对稳定的组件中,应该包含一些抽象类,这样就可以对它进行扩展。

       SAP和SDP一起构成了组件的DIP(依赖倒转原则)。SDP要求依赖应该朝着稳定的方向进行,而SAP则规定稳定性意味着抽象性,组件的稳定程度要与其抽象程度一致。因此,依赖也应该朝着抽象的方向进行。根据DIP,为了降低类与类之间的耦合度,我们要针对接口编程,而不要针对实现编程,同理,为降低组件之间的耦合度,我们要针对抽象组件编程,依赖应该沿着抽象而又稳定的组件来进行。

      由于在一个组件中可以包含多个类,其中有些类是抽象的,而另一些类是具体的,因此在评价一个组件的抽象程度时,可以通过计算“抽象类的数量占类总数的百分比”来度量一个组件的抽象性。

抽象性度量

       为了度量组件的抽象性,需引入以下几个度量指标:

       Nc(The number of classes):组件中类的总数。

       Na(The number of abstract classes):组件中抽象类的数目,一个抽象类中至少包含一个抽象的方法,抽象类不能被实例化。

       A(Abstractness):抽象性因子。

       A = 0表示组件中没有任何抽象类;A = 1表示组件中所有的类全部都是抽象类。

       我们可以先计算出每一个组件的抽象性因子A,结合SAP和SDP两大原则,不难得知,依赖需要沿着稳定的方向进行,也需要沿着抽象的方向进行,可以通过比较一个依赖链上每个组件的A值来判断依赖链是否需要进行调整,A值可以作为一个改善和调整依赖链的指标,但这并不是强制性的。

主序列分析

       在Bob大叔的ASD一书中,有专门的一节来分析稳定性和抽象性之间的关系,并得到了一条主序列(Main Sequence)。Sunny觉得这个过程有点像是在做软件工程的理论研究,与软件工程的实践还是有所区别的,但是,软件工程的发展既需要理论研究的支持,又需要实践经验的验证,而且了解一下人家如何做研究,本身也是一件挺有意思的事情,接下来我介绍一下Bob大叔如何分析组件稳定性和抽象性之间的关系。

      为了更好地研究组件的稳定性和抽象性,我们可以引入了一个二维坐标图,其中抽象性A作为纵轴,不稳定性I作为横轴,纵轴和横轴的坐标刻度都是从0到1,最稳定、最抽象的组件位于坐标左上角(0,1)处,也就是说当不稳定性I=0,抽象性A=1时,组件是最稳定、最抽象的;而那些最不稳定、最具体的组件位于坐标的右下角(1,0)处,此时不稳定性I=1而抽象性A=0。理想情况下,我们希望组件都能够落在这两个位置附近,也就是说,组件要么是最稳定最抽象的,要么是最不稳定最具体的,但是这毕竟只是理想情况,绝大部分组件的抽象性和稳定性都具有一定程度,位于这两个点之间。

      Bob大叔认为,在(0,0)附近的组件,是一些具有高度稳定性且具体的组件,但是这种组件僵化程度很高,因为它是具体的,无法对其进行扩展,又因为它是高度稳定的,因此很难对它进行更改。简单来说,位于此处的组件,它会被很多其他组件所依赖(稳定性),但是它很难扩展和修改(具体性)。(0,0)附近的区域被称为痛苦地带(Zone of Pain)

      在(1,1)附近的组件,也不是一个好的位置,此处的组件虽然具有最低的稳定性和最高的抽象性,但是由于其稳定性低,因此没有其他组件依赖它们,即使具有很高的抽象性也不能得到使用。所以这个(1,1)附近的区域被称为无用地带(Zone of Uselessness)

      我们希望所设计的组件能够尽量远离这两个区域,而将距离这两个区域都最远的轨迹点连接成一条线,这条线就是连接(1,0)和(0,1)点的线,这条线称为主序列(Main Sequence),所图1所示。

图1 主序列和被排除的区域示意图

       位于主序列上或者靠近主序列的组件都具有一定程度的稳定性和抽象性,虽然组件的理想位置是主序列的两个端点,但是在实际项目中,大部分组件能够位于主序列上或者主序列附近就已经很不错了。

      为了更好地度量一个系统的组件设计是否足够好,最后再介绍一个度量:到主序列的距离

      到主序列的距离(简称距离)是指一个组件到主序列之间的距离(D),计算公式如下:

      该度量值的取值范围是[0,0.707]。

      除此之外,还可以用一种规范化距离(D')来表示,计算公式如下:

      D'的取值范围是[0,1],0表示组件正好位于主序列上,1表示组件到主序列的距离最远。

      通过使用这个度量,我们可以全面分析一个组件设计方案和主序列之间的一致性。首先可以计算出每个组件的D值,然后对所有D值不在0附近的组件进行复查和调整。这将有助于设计者确定哪些组件更容易维护,哪些组件对变化不敏感、更加稳定。

      此外,还可以对组件设计方案进行统计学的分析,例如可以计算出设计中所有组件的D度量值的均值和方差,并且期望得到一个均值和方差都接近于0,也就是尽量符合主序列的设计。通过方差分析,可以找出一些比较特殊的组件,如图2所示,在这个分布图中,大部分组件都沿着主序列分布,但是也有一些组件离主序列较远,标准偏差Z值超过1甚至2,我们需要留意这些偏离较大的组件,尽量找出是什么原因导致它们非常抽象但具有较少的依赖者,或者非常具体但是有较多的依赖者,必要时我们需要对这些组件进行重构,进一步改进系统的设计。

图2 组件的D值分布图(示例)

       除此之外,我们还可以绘制每个组件的D'度量值随时间变化的分布图,看是否随着系统版本的升级或者演化导致某个(或某些)组件的D'值发生了较大的改变,如果在某个版本中一个组件的D'值发生异常变化或者超过预先设定的一个阈值,需要找出改变的原因,以便对系统实施更好的重构。

 总结 

    组件设计以及组件之间的依赖关系是有好坏之分的,通过应用这六个组件设计原则,可以在一定程序上改进组件的设计。

    重用-发布等价原则(REP):重用的粒度就是发布的粒度。

    共同重用原则(CRP):一个组件中的类需一起被重用。如果你重用了组件中的一个类,那么就要重用其中所有的类。

    共同封闭原则(CCP):一个组件中的所有类对于同一种类型的变化应该是共同封闭的。一个变化若对一个组件产生影响,则将影响该组件中所有的类,而对其他组件不造成影响。

    无环依赖原则(ADP):在组件的依赖关系图中不允许存在环。

    稳定依赖原则(SDP):朝着稳定的方向进行依赖。

    稳定抽象原则(SAP):组件的抽象程度应该与其稳定程度一致。

      至此,6个组件设计原则全部介绍完毕,虽然有些原则的分析过于理论,看起来也挺枯燥的,但是一旦深入进去发现还是挺有意思的,希望这几篇文章对大家能够有所帮助!吐舌头

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK