对于任何还不熟悉设计模式的人来说,在对这个领域进行简短的纵览之后,可能会留下这样的印象:设计模式是一个市场营销大骗局,它不过是一些简单的编程技术,或者不过是计算机科学家的玩物。尽管这些印象都有那么一点道理,然而设计模式的确是职业C++程序员工具箱中不可或缺的组件。
设计模式是一个被反复谈论的架构主题。它为特定上下文中的常见设计问题提供了解决方案,并描述了这种解决方案的结果。设计模式不仅仅是对技术的简单描述,它还是从现有的成功实践一点一滴汇集起来的设计智慧的具名封装,并以窬交流和复用的方式编写而成。模式关乎程序员之间的顺畅交流。
从实践的角度来看,设计模式具有两个重要的属性。首先,它们描述了经过验证的、成功的设计技术,这些技术可以按上下文相关的方式进行定制,以便满足新的设计场合的要求。其次,并且可能更重要的是,在提及某个特定的应用时,不仅包括其中用到的技术,还包括应用该模式的动因以及应用后所达到的效果。
这类事物并不是什么新东西。考虑一个来自算法领域的类比。考虑如下声明:“有一个未排序的序列,必须要进行很多次搜索。因此,希望对其进行快速排序,并且使用二分查找来执行每一个查找。”能够使用术语“快速排序”和“二分查找”,这种价值是不可估量的,不但在设计方面如此,在就该设计与受过教育的同事进行交流时也如此。当我说“快速排序”时,我的同事知道我正在排序的序列具有随机存取结构,并且它的排序时间复杂度的O(nlog2n),同时该序列中的元素可以采用类似小于操作符进行比较。当我说“二分查找”时,我的同事知道序列已经被排序过了,定位感兴趣的元素所执行的比较操作的时间复杂度为O(log2n),并且存在一个适当的操作来对序列中的元素进行比较。标准算法所具有的共享的知识以及标准词汇表,不但允许高效地记录文档,而且允许对设计方案进行有效的评议。比如说,如果我计划对一个单向链接表结构来执行这个查找和排序过程,我的同事立刻会自鸣得意地哈哈大笑,并指出在这种情况下我不能使用快速排序并且可能不希望使用二分查找。
在设计模式出现之前,在对面向对象设计的文档化、交流以及高效地评议方面,这些优点都不具备。我们被迫低水平地描述我们的设计,这种方式低效且不够精确。这并不是说用于复杂面向对象设计的技术尚不存在,而是这些技术尚未以一个共享的、通用术语的方式为整个编程社群所用。设计模式解决了这个问题,我们现在可以像描述算法设计一样高效、毫无歧义地描述面向对象设计。
举个例子,当我们看到Bridge模式被应用到某项设计中时,我们知道在一个简单的机制层面,抽象数据类型实现被分离成一个接口类和一个实现类。此外,我们知道这样做的原因是为了将接口从实现强有力地分离出来,这样,对实现的改变将不会影响到使用接口的用户。我们还知道这种分离会带来运行期开销,知道应该怎样对抽象数据类型的源代码进行布局,还知道许多其它细节。模式的名字是关于某项技术的诸多信息和经验的高效且无歧义的“句柄”,在设计和文档中小心并正确地使用模式和模式术语,可以使代码和设计更加明确。
那些严谨的模式专家有时以某种文献的形式来描述模式,这种描述遵循某种正式的结构。还有几种常见的变体也在使用,但不管哪种描述方式,均包含下面4个必不可少的部分:
首先,设计模式必须具有一个毫无歧义的名字。例如,术语“包装器(Wrapper)“对于设计模式命名来说就没有什么意义,因为它早已被广泛使用并且具有许多不同的含义。使用“Wrapper”这样的术语来命名某种设计模式只会带来混淆和误解。实际做法是:以前在"Wrapper"名下的设计技术指派为"Bridge" "Strategy" "Facade" "Object Adapter"以及其它一些模式名字。使用精确的模式名字比使用不那么精确的名字具有“明显”的优势,就像术语“二分查找”比“查找”更精确一样。
其次,模式描述必须定义该模式所能解决的问题。这种描述可以相对宽泛,也可以相对狭窄。
再次,模式描述要记述该问题的解决方案。根据陈述的问题,该解决方案可以相对高级,也可以相对低级,但无论如何,它应该具有足够的通用性,以便可以根据问题可能出现的不同上下文进行定制。
最后,模式描述要记述将该模式应用于某个上下文的后果。在应用该模式后,该上下文是如何发生改变的?不管是变好,还是变坏。
拥有模式的知识可以使一名糟糕的设计师摇身一变成为一名优秀的设计师吗?呃,是给出另一个类比的时候了,设想你被迫学习某一门让人痛苦的数学课,它的期末考试内容是证明某个领域中的许多定理。如果才能从这门课中死里逃生呢?当然,最显而易见的方式是成为一个天才。它从最初的原理开始,进而研究整个数学分支的基础知识,最终证明那些定理。一个更为实际的途径是,你牢记并消化该数学领域中的大量定理,并使用它所具备的任何天赋的数学能力、灵感以及好运去选择适当的辅助定理,然后以某种逻辑“胶水”将它们粘合在一起,从而最终证明新的定理。是的,甚至对于那些“传送中的天才”来说,这种方式都是很有优势的,因为基于现成的定理来证明会更高效,同“凡夫俗子”交流起来也更容易。当然,熟悉辅助定理并不能保证一个可怜的学数学的学生通过考试,但这类知识至少可以使其能够理解别人给出的证明。
同样的道理,从最初的原理进而到复杂的面向对象设计也是颇为无趣的,而且与他人交流最终设计也很困难。组合使用各种设计模式来生成面向对象设计,类似于在数学中使用辅助定理来证明一个新的定理。设计模式常常被描述为“微架构(Micro-architecture)“,它们可以与其它模式进行组合从而生成一个新的架构。当然,选择适当的模式并有效地对其进行组合,也是需要设计方面的专家经验和天资禀赋的。不过,一旦设计完成后,甚至你的经理都能够理解完整的设计方案,只要他具备一些必需的模式方面的知识即可。
阅读(1452) | 评论(0) | 转发(0) |