图解设计模式——学习设计模式之前需要了解的信息


在学习设计模式之前,我们先来了解几个小知识,以便更好地理解设计模式

设计模式并非类库

为了方便地编写面向对象程序,我们会使用类库,但是设计模式并非类库。

与类库相比,设计模式是一个非常普遍的概念。类库是由程序组合而成的组件,而设计模式则用来表现内部组件是如何被组装的,以及每一个组件是如何通过相互关联来构成一个庞大系统的。

我们以白雪公主的故事为例来思考一下。在讲述故事梗概时,我们并不需要知道在演绎这个故事的电源中到底是谁在扮演白雪公主、谁扮演王子。与介绍演员相比,讲述白雪公主与王子之间的“关系”更为重要。因为并非特定的演员扮演的“白雪公主”才是白雪公主,不论谁来扮演这个角色,只要是按照白雪公主的剧本来进行演出,她们就是白雪公主。重要的是这个故事中有哪些出场人物,他们之间是什么样的关系。

设计模式也是一样的。在回答“什么是 abstract factory 模式”时,阅读具体的示例代码有助于我们理解答案,但是并非只有这样特定的代码才是 abstract factory 模式。重要的是在这段代码中有哪些类和接口,它们之间是什么样的关系。

但是类库中使用了设计模式

设计模式并非类库,但是很多标准类库中都使用了很多设计模式。掌握了设计模式可以帮助我们理解这些类库所扮演的角色。

典型的例子如下所示,在以后单独介绍各种设计模式的章节中,我们还会进一步学习:

  • java.util.Iterator 是用来遍历元素集合的接口,这里使用了 iterator 模式
  • java.util.Observer 是用来观察对象状态变化的接口,这里使用了 Oserver 模式
  • 还有很多使用了 factor method 模式:java.util.Calendar 类的 getInstance 方法、java.secure.SecureRandom 类的 getInstance 方法、java.text.NumberFormat 类的 getInstance 方法
  • java.awt.Component 和 java.awt.Container 这两个类中使用了 Composite 模式

示例程序并非成品

设计模式的目标之一就是提高程序的可复用性;也就是说,设计模式考虑的是怎样才能将程序作为“组件”重复使用。因此,不应当将示例程序看做成品,而应当将其作为扩展和变更的基础。

  • 有哪些功能可以被扩展
  • 扩展功能时必须修改哪些地方
  • 有哪些类不需要修改

从以上角度看待设计模式可以帮助我们加深对设计模式的理解

不只是看图,还要理解图

接下来将以图解的方式讲解设计模式,其中主要使用的有类图和时序图(具体请参考 UML )。这些图并非只是简单的画,只瞥一眼是无法理解其中内容的。

在看类图时,首先看长方形(类),然后看它们里面的方法,并确认哪些是普通方法、哪些是抽象方法。接着确认类之间的箭头的指向,弄清楚究竟是哪个类实现了哪个接口。只有像这样循序渐进,一步一步对图中的内容刨根问底才能真正理解这幅图的主旨。

相比于类图,时序图理解起来更加容易一点。按照时间顺序自上而下一步一步确认哪个对象调用了哪个对象,就可以慢慢理解每个对象在模式中所扮演的角色。

只瞥一眼图是无法理解图中深藏的内容的,必须深入理解这些图。

自己思考案例

不要只是阅读书中的案例,还需要自己尝试思考一些案例。

另外,我们还需要在自己进行设计和编程时思考一下学习过的设计模式是否适用于当前场景。

理解角色——谁扮演白雪公主

设计模式如同电影一样,类和接口这些“角色”之间进行各种各样的交互,共同演绎一部精彩的电影。在电影中,每个人都必须按照自己的角色作出相应的行为。主人公的行为必须像主人公,敌人则必须对抗主人公。女主角也会出场,将剧情推向高潮。

设计模式也一样。在每一种设计模式中,类和接口被安排扮演各自的角色。各个类和接口如果不能理解自己所扮演的角色,就无法深入理解电影整体的剧情,无法扮演好自己的角色。这可能导致主人公屈服于地方,或是女主角变成了坏人;又或是将喜剧演成了悲剧,将纪实片演成了科幻片。

在接下来,我们将学习一种设计模式。同时我们也需要了解设计模式中出现的角色。在阅读示例代码时,不要只盯着代码本身,而要将关注点转移到角色上来,在阅读代码的时候,要思考各个类和接口到底在模式中扮演着什么角色。

如果模式相同,即使类名不同,它们所扮演的角色也是相同的。认清它们所扮演的角色有助于我们理解模式。这样,哪怕换了演员,我们依然可以正确理解剧情。