包复用原则&实践

理论部分

包的复用原则可以分为两大类

组件的内聚性原则:粒度

重用-发布等价原则(Reuse-Release Equialence Principle, REP)

  重用的粒度就是发布的粒度。

  你自己如果是某个可重用组件(包)的用户,这个组件(包)必须满足那些条件你才会乐于使用呢?

  1)有清晰的文档和接口说明

  2)有人维护

  3)发布新版本时能够得到及时的通知,而且如果当前版本已经满足你的要求,那么你有权要求不跟着升级,即新版本发布后老版本仍然能够work的很好。

  4)组件中的类都是可重用的,不能包含不可重用的类。比如一个可复用包中却包含一个只有在特定系统,特定约束下才可以使用的class,这会让人产生疑惑。

  5)你复用的这个组件有且只有一个明确的目的,比如你想复用的是一个金融系统的框架,那么就不能在这个包中还有机械软件计算的组件。

共同重用原则(Common-Reuse Principle,CRP)

  一个组件中的类应该是共同重用的。如果重用了组件中的一个类,那么就要重用组件中的所有类,否则就说明该组件违反了CRP。这个原则告诉我们,哪些类不应该放在一起。当一个组件使用了另外的一个组件时,二者之间就产生了依赖关系,哪怕只是使用了另外组件中的一个类,也不会导致依赖关系变弱,当被依赖的组件发生变化时,使用者必须升级,哪怕产生变化的原因其实跟使用者依赖的那个类没有任何关系,这就给使用者带来了不必要的麻烦。因此作为用户,当我想要依赖某个组件时,我肯定希望引起这个组件变化的原因越少越好。

共同封闭原则(Common-Closure Principle,CCP)

  组件中的所有类对于同一种性质的变化应该是共同封闭的。一个变化若对一个封闭的组件产生影响,则将对该组件中的所有类产生影响,而对于其他组件则不造成任何影响。

  REP和CRP从用户的角度希望包尽量小。而CCP从开发者的角度考虑希望包大一些,有人说CCP是面向对象设计原则SRP对于组件的重新规定,我没有充分理解,不完全赞同。

组件的耦合性原则:稳定性

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

  在组件的依赖关系图中不允许出现环。

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

  朝着稳定的方向进行依赖。如果一个组件,对外不依赖任何其他组件,而都是其他组件依赖它,那么这个组件时最稳定的。反之,如果再没有组件依赖它,而都是它依赖其他组件,那么这个组件是最不稳定的。

  关于稳定性的公式

    I=Ce/(Ca+Ce)

    I:不稳定性 Ce:该组件依赖外部组件的数目 Ca:外部组件依赖该组件的数目

    I=0 则最稳定,I=1最不稳定

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

  组件的抽象程度应该与其稳定程度一致。这个和面向对象设计OCP原则是一致的,变化的与不变的分离,把变化的进行封装。稳定的组件应该也是抽象的(不变的),不稳定的组件应该是具体的(可能变化的)。

实践部分

我们部门对外提供基础服务,这些服务都是以soa的形式提供的。

目前我们开发一个soa服务,大概需要如下几个工程(处于商业保密的考虑,凡是可能涉及到公司架构或者业务信息的地方我都用xxx代替):

1. xxx-service:soa服务的核心逻辑

2. xxx-server:该服务的Controller

3. xxx-api :用户调用该soa服务的api接口

4. xxx-model : soa服务依赖的一些模型对象,这些对象有的是简单的值对象,有的则含有业务逻辑是个真正的Bean。这些对象可能作为用户api的调用参数,因此xxx-model可能会被xxx-service和xxx-api同时依赖。

目前,xxx-model工程中包含所有soa服务的model对象,而不是以soa服务为单位。这样带来的问题是:

当用户要使用某个soa服务A的时候,他需要依赖xxx-api和xxx-model,而后者不仅包含A的model还包含B的,C的。。。,导致用户实际上与所有soa服务的model对象产生了依赖,而实际上用户对B或者C可能根本不关心。一个直接的表现就是用户通过maven管理生成的发布包非常之大,而且还非常容易产生各种因其他服务而引起的错误。

有人认为造成这种局面的原因是xxx-model中很多对象不是简单的值对象而是包含很多业务逻辑,导致这些对象有很深的依赖。

我认为这不是根本原因,根本原因是xxx-model工程违反了“共同重用原则(CRP)",如果以soa服务为单位组织xxx-model,那么即使某个soa的xxx-model中的对象有很多业务逻辑,有很深的依赖,也不会影响不依赖该soa服务的用户。前人们只所以把所有model类都放在一个工程里,其实是从开发者方便的角度考虑过多的结果,即过度的遵守了CCP而导致严重的违反了CRP,导致用户很受累。

所以,一个更合理的工程组织方式(这里简单认为工程组织方式就是jar包发布方式)应该是:对于soa服务A,它由如下工程构成

A-service

A-server

A-model(可选的,有些服务接口很简单,可能就不需要model工程)

A-api

发布时,以上4个工程作为整体(或者说原子)来发布。

以后在重构或者设计新的soa服务时,请大家注意这个问题。

posted on 2011-08-17 17:43  wenfeng762  阅读(660)  评论(0编辑  收藏  举报