一个好的系统设计应该有如下的性质:可扩展性(Extensibility),灵活性(Flexibility),可插入性(Pluggability)。

  • 可扩展性——新的性能可以很容易的加入到系统中去,就是可扩展性。是“过于僵硬”的属性的反面。
  • 灵活性——可以允许代码修改平稳地发生,而不会波及到很多其它的模块,这就是灵活性。是“过于脆弱”的属性的反面。
  • 可插入性——可以很容易的将一个类抽出去,同时将一个有同样接口的类加入进来,这就是可插入线。这是“黏度过高”的属性的反面。

怎样才能做出一个符合这三个要求的设计呢?关键是恰当地提高软件的可维护性和可复用性。

复用不仅仅是代码的复用,虽然代码复用确实是复用的一个初等形式。代码的剪贴复用、算法的复用、数据结构的复用都是传统的复用种类,它们都各有优点,也各有缺陷。传统的复用方案的一个致命缺陷就是复用常常是以破坏可维护性为代价的。
比如两个模块A和B同时使用另一个模块C中的功能。那么当A需要C增加一个新的行为的时候,B可能不需要,甚至不允许C增加这种新行为。如果坚持使用复用,就要以系统的可维护性为代价;而如果从保持系统的可维护性出发,就只好放弃复用。可维护性与可复用性是有共同性的两个独立特性,它们就像是两只在独立奔跑的兔子,如下图所示。

因此,一个重要的概念就是支持可维护性的复用,也就是在保持甚至提高系统的可维护性的同时,实现系统的复用。那么怎样才能设计一个系统,已达到提高可维护性的复用的目的呢?换言之,怎样才能抓住这两只同时在奔跑的兔子呢?

在面向对象的设计里面,可维护性是以设计原则和设计模式为基础的,请参见下面的分析。

  • 首先,恰当地提高系统的可复用性,可以提高可扩展性。允许一个具有同样接口的新的类替代旧的类,是对抽象接口的复用。客户端依赖于一个抽象的接口,而不是一个具体的实现类,使得这个具体类可以被另一个具体类所取代,而不影响到客户端。系统的可扩展性是由“开-闭”原则、里氏代换原则、依赖倒转原则和组合/聚合复用原则所保证的。
  • 其次,恰当地提高系统的可复用性,可以提供灵活性。在一个设计得当的系统中,每一个模块都相对于其它模块独立存在,并只保持与其他模块尽可能少的通信。这样一来,在其中某一个模块发生代码修改时,这个修改的压力不会传递到其它模块。系统的灵活性是由“开-闭”原则,迪米特法则,接口隔离原则所保证的。
  • 最后,恰当地提高系统的可复用性,可以提高系统的可插入性。在一个符合“开-闭”原则的系统中,抽象层封装了与商业逻辑有关的重要行为,这些行为的具体实现由实现层给出。当一个实现类不再满足需要,需要以另一个实现类取代的时候,系统的设计可以保证旧的类可以被“拔出”,新的类可以被“插入”。系统的可插入性是由“开-闭”原则,里氏代换原则,组合/聚合复用原则以及依赖倒转原则保证的。

依照这些设计原则进行设计,就可以抓到可维护性、可复用性这两只同时在奔跑的兔子。

end.