模式2:Module Reuse

 由  Ruici 发布

描述

模块复用:在模块层面上强调复用能力

面向对象编程范型为软件开发提供了一系列新的方法、原则和模式,其最重要的目的就是提高软件复用的程度。但是,随着软件系统规模的日益庞大以及越来越高的复杂度,强调类层面(class-level)上的复用的面向对象方法难免遇到了一些困境。

为了更有效的复用,就需要更高层次的复用单元——模块(module),在Java中就是JAR文件,代码被组织聚合在模块里并且可以被单独部署。Reuse Release Equivalence Principles更直观的说明了这一点:

The unit of reuse is the unit of release

也就是说,我们应该更加注重模块层面的复用。在模块内部,仍然应该使用面向对象的各种设计概念来构造可扩展、可配置的类,将它们聚集于一个内聚并且可以独立部署的模块内。

实现变种

在设计可复用的模块时有几个需要关注重点关注的地方

横向和纵向

横向(Horizontal)模块可以认为是贯穿所有业务领域的公共部分,一般来说不包含某项业务相关的具体逻辑。它们是很容易被复用的,因为模式基本一致并且为广大开发者所熟知。大部分开源软件,例如Java Web开发最常用到的SSH(Struts, Spring, Hibernate)都可以归为这一类。

纵向(Vertical)模块则恰恰相反,是针对于某一特定领域的特定业务而存在的。它们更加难于被复用,因为特定领域中的需求,往往还与组织机构相关,这一方面的需求往往是多变而不可预测的。因此,在创造纵向模块时,使之复合最小功能、单一职责原则就非常重要了,这样能够最大限度的让系统中其他模块复用其逻辑。也就是说,保持细粒度(fine-grained)是非常重要的。

服务

多年以来,业界普遍认为服务会引起软件复用的革命性变化。但实际上服务是基于模块乃至软件体系结构(Software Architecture)的,一个优秀的体系结构从类结构到模块结构的要求都是非常高的,有了这些才会体现出服务层面的优越性。反过来说,当一个软件系统的模块都是松耦合(loosely-coupled)并且能很好的在运行时连接在一起,那么基于这些模块也很容易的能够组装出你所需要的服务

模块管理

模块管理是非常困难的,模块数量庞大加之每一个模块都有可能有不同的版本存在,这就对保证模块间的正确依赖关系造成了很大困难。那么通过版本控制系统将模块管理起来是一个很好的选择,JAA作者认为将模块对应的二进制文件放入仓库,但我认为有Maven这样优秀的管理系统,通过自己假设私服来实现版本管理可能是一个更棒的选择。

上面提到的是编译、构建时刻的模块管理,在运行时刻同样也需要考虑模块间的版本以及依赖关系。OSGi正是一个提供了这样特性的优秀模块化框架。另外,为了完成这个目标,除了框架的支持似乎没有其他更有效的办法了。

结果

强调模块层面上复用能够更大程度上使得复用更加有效。虽然说通过一些已经事先构建好可以部署运行的模块来组装新的应用到现在还是一个没有达成的梦想,但是这种构造模块的方式通常也能够对软件的生产、构建乃至交付起到积极的作用。

另一方面,考虑模块复用通常也会陷入一个两难的抉择中:复用程度高就会导致系统被分为很多小的细粒度的模块,这用增加了管理难度;而大的模块管理更加方便,但是又不利于复用。这中间的权衡、折中(trade-off)往往也是开发中一件极为具有难度和挑战的事情。

例子

业务对象往往需要通过从XML等等数据格式中创建、获取。那么为了保证业务对象还能够被其他模块复用,并且和XML相关的处理逻辑解耦(可以通过面向对象的设计模式来实现)。

总结

Reuse Release Equivalence Principle表明软件的复用和发布针对的单元是统一的,模块则是唯一满足这个条件的软件实体,好的模块设计则会为软件开发团队日后的复用带来极大的便利。

查看评论