设计模式 学习笔记 之五

第6章 接口隔离原则

接口隔离原则(Interface Segregation Principle)可被表述为:客户模块不应该被强迫依赖于不使用的方法。

在前一章中,我们学习了依赖抽象原则,并且指出:客户模块给服务提供者模块设定要求,这种要求以抽象接口的形式表示。那么,接口隔离原则就进一步指出:抽象接口必须准确地反映客户模块的要求,不能把客户模块不需要或用不到的服务也包括到抽象接口中来。

为什么不应该把客户模块不需要的服务放入抽象接口中?这个问题可以从服务提供者的角度来看。服务提供者模块必须实现抽象接口中规定的所有服务,才能称其为一个合格的服务提供者。但是,如果有一项服务,它被抽象接口所规定,但客户模块却又没有使用,可是服务提供者却必须实现并维护这项服务,这是不是使系统具有了“不必要的复杂性”呢?这样的设计,显然并不是优良的设计。因此,让抽象接口仅指定客户模块真正使用的服务——不多不少,能够使系统的复杂性最小化。下面来看一个例子。

例子:ATM机业务

假设我们现在开发一个ATM机程序。该ATM机允许它的用户完成存款、取款和转账业务。初始设计是这样的:Transaction处于业务逻辑层,用于对用户业务建模。UI处于表现层,用于向用户显示业务流程和读取信息。在这个设计中,业务逻辑层是上层,表现层是下层,而Transaction模块是客户模块,而UI是服务提供者模块。详细的设计图如下。

clip_image002

这个设计大体上是不错的,它遵循了前一章学习的依赖抽象原则,但是它却违背了本章所讲的接口隔离原则。对于DepositTransaction类来说,它不需要UI接口中的requestWidthdrawalAmount()和requestTransferAmount()方法。对其它两个类也存在类似的问题。

怎么解决这个问题?一个直观的想法是:既然UI接口是一个杂凑体,那么干脆把它拆分开,从而得到下面的这个设计。

clip_image004

这个设计比起先前的设计来是更加优良的吗?可能有不少人仅从直觉上分析也不会认同,因为在表现层中现在一下子冒出来许多新的类。而且可以想象,当有新的ATM机业务引入的时候,类似的“类爆炸”问题还会更加严重。怎么解决这个问题?

让我们再来回顾一下设计。初始设计的问题在于把所有的UI服务不分青红皂白都塞进UI接口中。这个问题在把UI接口拆分成3个单独的接口之后得到了解决。但是,这同时也带来了另一个问题,即表现层的类爆炸问题。那么我们可不可以在表现层中又把上层已经拆分的接口重新合并成一个接口呢?可以尝试一下。这样子得到如下的设计。

clip_image006

这个新的设计比先前看起来“清爽”多了。我们既保持了业务层的接口隔离,又克服了表现层类爆炸的问题,使得这个问题得到了较好的解决。实际上初始设计方案是桥梁模式的应用,而最终的设计方案则可以看作是经过接口隔离原则指导后的改良版本。

有时候,一个接口可以被拆分是因为它本身担负了不止一个职责,也就是说,它违背了单一职责原则。我们下面来看一个例子。

例子:调制解调器

假设我们在开发一个加密数据传输系统。该系统会使用到华为和思科的调制解调器。我们把这种情形建模如下。

clip_image008

系统一开始都运转正常。现在注意,有一到,新的需求来了。系统被要求支持一种称为DeadModem的传输设备,这种设备不需要像传统的调制解调器那样拨号和挂断,而是直接收发数据。系统被要求同样支持华为和思科的DeadModem。

为此,我们作出了如下的设计。

clip_image010

系统这样设计当然是可以的,但是你可能也注意到了这个设计中存在着“不必要的重复”。有办法解决它吗?

我们先来想想这个问题为什么会出现。仔细分析一下,Modem接口实际上担负了两个职责:一是建立连接,二是数据收发。而新的DeadModem设备并不需要建立连接,这导致它无法从Modem接口派生,而只能是“另立门户”。

既然Modem接口承担了两项职责,我们可不可以把这两项职责分拆开来呢?也就是像下图所示这样。

clip_image012

这个设计看起来好一些。重复性被消除了,同时原先的ModemClient也没有受到接口拆分的影响。当然,Modem接口仍然是担负了两个职责,这一点违背了单一职责原则。

第7章 设计原则小结

至此,我们对设计原则的学习完毕。我们要在最后强调的是:设计原则是指导意见,但不是死守的教条。设计原则应该用来指导实际的设计,用来评判设计的质量,但这并不代表设计原则就一点也不能违背,也不代表凡是违背了某条或某些设计原则的设计都是差的设计。就像前一章中ATM机业务和调制解调器的例子中,UI接口违反了接口隔离原则,Modem接口也违反了单一职责原则,但最终的设计仍然是优良的设计。把设计原则当成指导而不是教条,尝试努力去遵循这些原则,但同进也要相信自己的设计直觉。当遵循设计原则与“创建简单而易于理解的设计”这个总原则相违背的时候,就应该牺牲一下设计原则,这样才能做出合理的设计。

posted @ 2011-04-17 19:01  李嘉 (Justin)  阅读(137)  评论(0编辑  收藏  举报