包的设计

目标:

  • 合理组织包来减少变化带来的影响。
  • 熟悉可供选择的UML包结构表示法。 如果开发团队种广泛依赖于某个包X,则他们肯定希望包X使比较稳定的,因为当包X发生变化时,需要不断地进行版本同步,并且要修改依赖于该包的软件,这样会导致版本过载。

上述的讨论时显而易见的,但有时开发团队对识别和固化被广为依赖的包并没有给与足够重视,并且因此经历了毫无必要的混乱而不知道其真正的原因。

本章在前一章关于层和包的讨论基础之上,为包结构的组织提出了更为细粒度的套索性方法,一次来减少变化带来的影响。其目标时创建健壮的物理包设计。

相比在Java中,人们在C++中会更快地感受到脆弱的依赖敏感性包组织所带来的痛苦,这是因为在C++中具有依赖敏感性更高的编译和链接;在一个类中的变更可能具有强烈的传递依赖型影响,会导致对大量类的冲编译和重链接。因此,这里的建议对C++项目特别有帮助,对例如Java或C#的项目也会带来一定的帮助。

实现模型中源代码的物理设计

这个问题设计物理设计的一个方面--为源代码进行打包的UP实现模型。

如果仅仅是在白板或CASE工具中绘制包设计,则我们可以将类型任意放置到功能上相关的包中。但是在进行源代码的物理设计时,需要将类型组织到物理单元,发布为java或c++的包。如果有许多开发者共享公共代码,则当这些包发生变化时,我们的选择将决定开发者受变化影响的程度。

组织包结构的准则

准则:包在水平和垂直划分上的功能性内聚

最基本的“直观性”原则时基于功能性内聚的模块化,将参与共同目的、服务、协作、策略和功能的强相关类型组织在一起。

除依据功能进行的非正式的猜测以外,也可以依据类型之间的耦合程度进行分组。

包内部的耦合程度和关系内聚,可以被定量地度量,尽管在实际项目中很少这样做。以下为求职者给出一种度量方法:

RC=内部关系的数量/类型的数量。

内部关系的数量包含属性和参数关系,继承以及包内类型之间的接口实现。RC的值越大表明包的内举行越强。

注意,这一度量指标不适用于仅包含接口的包,它适用于包含实现类的包。

非常小的RC值意味着:

  • 包中包含相互无关的事务,彼此没有分离开。
  • 保重包含相互无关的事务,设计者故意这样安排。通常,包含独立服务的工具包就是如此。此时,RC值的大小并不重要。
  • 包含几个高内聚的子集,但整体内聚程度不高。

准则:由一族接口组成的包

将一组功能上相关的接口放入单独的包,与其实现类分离。

准则:用于正式工作的包和用于聚集不稳定类的包

包时开发u哦东和产品发布的基本单元,很少有仅在一个类上工作或者发布一个单独类的情况。如果一个包不是非常大或者非常复杂,通常会由一个开发者来复杂包内的所有类型。

假设:

  1. 有一个包含30个类的大型包P1
  2. 其中有10个类经常被修改和重新发布。

在此情形下,将P1分成P1-a和P1-b两个部分,P1-b包含10个经常变动的类。

这样,包被分解为较稳定胡哦不稳定的两个子集,或者更为普遍地分成与工作相关的组。也就是说,如果包中的大部分类型堵在一起工作,那么这种分组形式就是有效的。

在理想情况下,通过将不稳定的部分分离为单独的包,应该只有较少的开发者依赖于P1-b而非P1-a,这样与重新发布更大的原始包P1相比,发布P1-b的新版指挥影响较少的开发者。

注意,这种重构去掘金后续工作的趋势。在早期迭代阶段确定良好的包结构时非常困难的。通常,包结构会随着细化迭代的深入不断地进行演化,这也应该时细化阶段的目标,当细化阶段结束时大部分的包结构会稳定化。

此准则阐明了基本策略:减少对不稳定包的广泛依赖。

准则:职责越多的包越需要稳定

如果具有大量职责的包不稳定,那么由于变化造成的影响有可能传播的更广。

有几种增强包的稳定性的方法:

  • 包中仅包含或者主要包含接口和抽象类。
  • 不依赖于其他的包,或者仅依赖非常稳定的包,或者封装了依赖关系一十七不受影响。
  • 包含相对稳定的代码,这些代码在发布之前经过充分的测试和精化。
  • 强制规定具有缓慢的变化周期。

准则:将不相干的类型分离出去

将能够独立使用或运行于不同语境的类型组织到单独的包中。不经过仔细考量,将公共功能组织起来并不能提供合理的粒度水平。

准则:使用工厂模式减少对具体包的依赖

减少对其他包中具体类的依赖是提高包的稳定性的一个途径。

准则:包之间没有循环依赖

如果一组包之间有循环依赖关系,那么可能需要将它们当作一个打爆对待。但是,我们并不希望这样做,发布大的包会增加影响其他元素的可能性。有两个解决方案:

  1. 将参与循环的类型分解出来形成较小的新包。
  2. 使用接口来打破循环。

使用接口打破循环的步骤如下:

  1. 重新定义在一个包中被依赖的类,使其实现新的接口。
  2. 在一个新包中定义新的接口。
  3. 重新定义依赖于原来类的类型,使其依赖于新包中的接口,而不是原来的类。

参考资料

results matching ""

    No results matching ""