第1章 设计模式基础
1.1 设计模式是什么
1.1.1 什么是模式
从字面上来看,模,就是模型、模板的意思;式,就是方式、方法的意思。综合起来,所谓模式就是:可以作为模型或模板的方式或方法。再简单点说就是可以作为样板的方式或方法,类似于大家所熟悉的范例。
1.1.2 设计模式的概念
按照上面的理解,设计模式指的就是设计方面的模板,也即设计方面的方式或方法。
1、设计模式是解决方案
根据上面对设计模式的定义可以看出,归根结底,设计模式就是一些解决方案。
所谓解决方案,就是解决办法,亦即是解决问题的方式或方法。通常所说的方案书,就是把解决方法文档化后形成的文档。
那么,能不能反过来说:解决方案就是设计模式呢?很明显是不行的。为什么呢?因为在解决方案之前还有一些定语,只有满足这些条件的解决方案才被称为设计模式。
2、设计模式是特定问题的解决方案
为什么要限制设计模式是“特定问题”的解决方案呢?
限制“特定问题”,说明设计模式不是什么万能灵药,并不是什么问题都能解决,通常一个设计模式仅仅解决某个或某些特定的问题,并不能包治百病。
因此不要迷信设计模式,也不要泛滥使用设计模式,设计模式解决不了那么多问题,它只是解决“特定问题”的解决方案。
3、设计模式是重复出现的、特定问题的解决方案
那么为何要这些特定问题是“重复出现”的呢?
只有这些特定问题“重复出现”,那么为这些问题总结解决方案才是有意义的行为。因为只有总结了这些问题的解决方案,当这些问题再次出现的时候,就可以复用这些解决方案,而不用从头来寻求解决办法了。
4、设计模式是用于解决在特定环境下、重复出现的、特定问题的解决方案
为什么要限制在“特定环境下”呢?
任何问题的出现都是有场景的,不能脱离环境去讨论对问题的解决办法,因为不同环境下,就算是相同的问题,解决办法也不一定是一样的。
5、设计模式是经过验证的,用于解决在特定环境下、重复出现的、特定问题的解决方案为又什么要限制是“经过验证的”呢?
每个人都可以总结一些用于解决在特定环境下、重复出现的、特定问题的解决方案,但并不是每个人总结的解决方案都算得上是设计模式,这些解决方案应该要有足够的应用来验证,并得到大家的认可和公认。只有经过验证的解决方案才算得上是设计模式。
没有得到验证的解决方案,假如也算设计模式而被大家大量复用的话,万一这个方案有问题呢?那么所有应用它的地方都会出错,都应该修改,这种复用还不如不用呢。
6、为何要强调“在软件开发中”
|
原因很简单,因为接下来要讨论的内容,就是软件开发中的设计模式,因此这里限制“在软件开发中”。
1.1.3 设计模式的理解
通过上面对设计模式概念的讲述,可以看出,设计模式也没有什么神奇之处,下面对设计模式再做几点说明,使读者进一步理解它。
n 设计模式是解决某些问题的办法。
要理解和掌握设计模式,其重心就在于对这些办法的理解和掌握,然后进一步深化到这些办法所体现的思想层面上,将设计模式所体现的思考方式进行吸收和消化,融入到自己的思维中。
n 设计模式不是凭空想象出来的,是经验的积累和总结。
从理论上来说,设计模式并不一定是最优秀的解决方案,有可能存在比设计模式更优秀的解决方案,也就是说设计模式是相对优秀的,没有最优,只有更优。
n 设计模式并不是一成不变的,而是在不断发展中。
本书仅仅讨论GoF的著作中所记载的、经典的设计模式,但并不是说只有这些设计模式。因为设计模式的发展从设计模式引入软件中以来,就从来没有停止过。
n 设计模式并不是软件行业独有的,各行各业都有自己的设计模式。
用大家身边的例子来说,比如医药行业,就有自己的设计模式。假设一个人感
冒了,到药店买感冒药,这个感冒药就是设计模式的一个很好体现。
u 经过验证的:药品上市前,会有大量的验证和实验,以保证药品的安全性。
u 特定环境下:这些药品是针对人的,不是针对其他动物的。
u 重复出现的:正是因为感冒会重复出现,研制药品才是有意义的。
u 特定问题:感冒药只是用来解决感冒问题的,不能解决其他问题,比如脚痛。
u 解决方案:药品本身就是该解决方案的具体体现。
经过上面的比较,你会发现,医药行业对设计模式的体现,一点也不逊色于软件行业。再说设计模式本身不是起源于软件行业,而是起源于建筑业。
1.1.4 设计模式的历史
设计模式起源于建筑行业,一位名叫Alexander的建筑师发现并总结了一些建筑行业的设计模式。
在20世纪90年代,准确地说是1995年,由于Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides合著的《设计模式——可复用面向对象软件的基础》一书的出版,正式掀开了软件业设计模式的序幕,这本书的四位作者被世人称为四人组,也有人将其称为“四人帮”,也就是大家常见的GoF(Gang of Four)。
1.2 设计模式有什么
1.2.1 设计模式的组成
在描述单个设计模式的时候,设计模式通常由以下部分组成。
n 模式名称:就是为每个设计模式取的名字,应好记忆,也好交流。
n 环境和问题:描述在什么场景下,出现什么样的特定的问题。
n 解决方案:描述如何解决这个问题。
n 效果:描述模式应用的效果,以及可能带来的问题,或者使用中需要权衡的问题。
在Java领域,对于设计模式的组成还有另外一种分法,就是按照设计模式所在的技术领域来划分,大致分为以下几类。
n Java设计模式:通常指GoF的《设计模式——可复用面向对象软件的基础》一书中提到的设计模式。
n JavaEE设计模式:通常指SUN《J2EE核心设计模式》一书中提到的设计模式。
n 其他领域的,包括但不限于:EJB设计模式、实时系统设计模式、多线程设计模式、架构模式等。
1.2.2 设计模式的分类
为了缩小范围,我们仅讨论Java设计模式,也就是GoF著作中提到的23个设计模式。对于这23个设计模式,GoF把它们分为三类。
n 创建型模式:抽象了对象实例化的过程,用来帮助创建对象的实例。
n 结构型模式:描述如何组合类和对象以获得更大的结构。
n 行为型模式:描述算法和对象间职责的分配。
当然也有按其他方式进行分类的,这里就不再讨论了。
1.3 设计模式的学习
1.3.1 为什么要学习设计模式
为什么要学习设计模式?实在是有太多的理由了,这里简单地罗列几点。
1、设计模式已经成为软件开发人员的“标准词汇”
很多软件开发人员在相互交流的时候,只是使用设计模式的名称,而不深入说明其具体内容。就如同我们在汉语里面使用成语一样,当你在交流中使用一个成语的时候,是不会去讲述这个成语背后的故事的。
举个例子来说:开发人员A碰到了一个问题,然后与开发人员B讨论,开发人员B可能会支招:使用“XXX模式”(XXX是某个设计模式的名称)就可以了。如果这个时候开发人员A不懂设计模式,那他们就无法交流。
因此,一个合格的软件开发人员,必须掌握设计模式这个“标准词汇”。
2、学习设计模式是个人技术能力提高的捷径
设计模式是很多前辈经验的积累,大都是一些相对优秀的解决方案,很多问题都是典型的、有代表性的问题。
学习设计模式,可以学习到众多前辈的经验,吸收和领会他们的设计思想,掌握他们解决问题的方法,就相当于站在这些巨人的肩膀上,可以让我们个人的技术能力得到快速的提升。学习设计模式虽然有一定的困难,但绝对是快速提高个人技术能力的捷径。
3、不用重复设计
设计模式是解决某些特定问题的解决方案。当我们再次面对这些问题的时候,就不用自己从头来解决这些问题,复用这些方案即可。
大多数情况下,这或许是比自己从头来解决这些问题更好的方案。一是你未必能找到比设计模式更优秀的解决方案;另外通过使用设计模式可以节省大量的时间,你可以把节省的时间花在其他更需要解决的问题上。
1.3.2 学习设计模式的层次
学习设计模式大致有以下三个层次。
1、基本入门级
要求能够正确理解和掌握每个设计模式的基本知识,能够识别在什么场景下、出现了什么样的问题、采用何种方案来解决它,并能够在实际的程序设计和开发中套用相应的设计模式。
2、基本掌握级
除了具备基本入门级的要求外,还要求能够结合实际应用的场景,对设计模式进行变形使用。
事实上,在实际开发中,经常会碰到与标准模式的应用场景有一些不一样的情况,此时要合理地使用设计模式,就需要对它们做适当的变形,而不是僵硬地套用了。当然进行变形的前提是要能准确深入地理解和把握设计模式的本质,万变不离其宗,只有把握住本质,才能够确保正确变形使用而不是误用。
3、深入理解和掌握级
除了具备基本掌握级的要求外,更主要的是:
|
比较复杂的应用中,当解决某个问题的时候,很可能不是单一应用某一个设计模式,而是综合应用很多设计模式。例如,结合某个具体的情况,可能需要把模式A进行简化,然后结合模式B的一部分,再组合应用变形的模式C…,如此来解决实际问题。
更复杂的是除了考虑这些设计模式外,还可能需要考虑系统整体的体系结构、实际功能的实现、与已有功能的结合等。这就要求在应用设计模式的时候,不拘泥于设计模式本身,而是从思想和方法的层面进行应用。
|
简单点说,基本入门级就是套用使用,相当于能够依葫芦画瓢,很机械;基本掌握级就是能变形使用,比基本入门级灵活一些,可以适当变形使用;深入理解和掌握级才算是真正将设计模式的精髓吸收了,是从思想和方法的层面去理解和掌握设计模式,就犹如练习武功到最高境界,“无招胜有招”了。要想达到这个境界,没有足够的开发和设计经验,没有足够深入的思考,是不太可能达到的。
1.3.3 如何学习设计模式
结合作者自身的经验,给出以下学习设计模式的建议。
(1)首先要调整好心态,不要指望一蹴而就,不可浮躁。
学习和掌握设计模式需要一个过程,不同的阶段看这些设计模式会有不同的领悟和感受。
不要指望真正的设计模式的书籍是既简单又有趣的,一看就懂的。那种书籍多是属于科普性质的书籍,只是让你简单了解一下设计模式。这也是为何很多朋友总感觉
|
“懂”设计模式,却不会在实际项目中应用设计模式。那是为你“懂”的程度不够。
(2)学习设计模式的第一步:准确理解每个设计模式的功能、基本结构、标准实现,了解适合使用它的场景以及使用的效果
(3)学习设计模式的第二步:实际的开发中,尝试着使用这些设计模式,并反复思考和总结是否使用得当,是否需要做一些变化。
(4)学习设计模式的第三步:再回头去看设计模式的理论,有了实际的模式应用经验再看设计模式,会有不同的感悟,一边看一边结合着应用经验来思考。比如:设计模式的本质功能是什么?它是如何实现的?这种实现方式还可以在什么地方应用?如何才能把这个设计模式和具体的应用结合起来?这个设计模式设计的出发点是什么?等等。可以有很多考虑的点,从不同的度对设计模式进行思考。
(5第四步:多次重复学习设计模式的第二步和第三步。也就是在实际开发中使用,然后结合理论思考,然后再应用,再思考……多次,直到达到对设计模式基本掌握的水平。
简而言之,大家要注意使设计模式的理论和实践相结合,理论指导实践,实践反过来加深对理论的理解,如此反复循环,成螺旋式上升。
事实上,到了基本掌握设计模式的水平后,最后能达到一个什么样的高度,因人而异,需要看个人的思维水平和理解水平。对于这个阶段,只有一个建议,那就是反复地、深入地思考,别无它法。到了思想的层面,就得靠“悟”了。
1.4 本书的组织方式
1.4.1 本书所讲述的设计模式的提纲
从第3章开始,本书详细地讲述了《设计模式——可复用面向对象软件的基础》GoF著一书所讲述的23个设计模式;第2章讲述的简单工厂,严格意义上并不算是标准的设计模式,只能算是一个热身运动。
1、第2章 简单工厂(GoF的著作中没有)
提供一个创建对象实例的功能,而无须关心其具体实现。被创建实例的类型可以是接口、抽象类,也可以是具体的类。
2、第3章 外观模式(GoF的著作中划分为结构型)
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
3、第4章 适配器模式(GoF的著作中划分为结构型)
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
4、第5章 单例模式(GoF的著作中划分为创建型)
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
5、第6章 工厂方法模式(GoF的著作中划分为创建型)
定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到其子类。
6、第7章 抽象工厂模式(GoF的著作中划分为创建型)
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
7、第8章 生成器模式(GoF的著作中划分为创建型)
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
8、第9章 原型模式(GoF的著作中划分为创建型)
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
9、第10章 中介者模式(GoF的著作中划分为行为型)
用一个中介对象来封装一系列的对象交互。中介者使得各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
10、第11章 代理模式(GoF的著作中划分为结构型)
为其他对象提供一种代理以控制对这个对象的访问。
11、第12章 观察者模式(GoF的著作中划分为行为型)
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
12、第13章 命令模式(GoF的著作中划分为行为型)
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
13、第14章 迭代器模式(GoF的著作中划分为行为型)
提供一种方法顺序访问一个聚合对象中的各个元素,而又不需暴露该对象的内部表示。
14、第15章 组合模式(GoF的著作中划分为结构型)
将对象组合成树形结构以表示“部分—整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
15、第16章 模板方法模式(GoF的著作中划分为行为型)
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
16、第17章 策略模式(GoF的著作中划分为行为型)
定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
17、第18章 状态模式(GoF的著作中划分为行为型)
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
18、第19章 备忘录模式(GoF的著作中划分为行为型)
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样,以后就可将该对象恢复到原先保存的状态。
19、第20章 享元模式(GoF的著作中划分为结构型)
运用共享技术有效地支持大量细粒度的对象。
20、第21章 解释器模式(GoF的著作中划分为行为型)
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
21、第22章 装饰模式(GoF的著作中划分为结构型)
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活。
22、第23章 职责链模式(GoF的著作中划分为行为型)
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
23、第24章 桥接模式(GoF的著作中划分为结构型)
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
24、第25章 访问者模式(GoF的著作中划分为行为型)
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
1.4.2 每个模式的讲述结构
1. 场景问题
1)某个实际应用
通过一个实际的应用来描述在某个场景下出现的某个问题,也就是模式要解决的问题。
2)不用模式的解决方案
先示例不用模式,如何来解决这个问题。
3)有何问题
分析不用模式的解决方案中存在的问题,指出需要寻找更好的解决方案。
2. 解决方案
1)某个模式来解决
首先是模式的定义,然后描述应用这个模式来解决上面提出的问题的解决思路。
2)模式结构和说明
使用UML画出模式的结构图,并说明各个参与者。
3)模式的示例代码
尽量准确的给出每个模式的基本实现的示例代码,算是模式的一个标准参考实现。
4)使用模式来重写示例
使用模式来重写前面“不用模式”所实现的示例,既作为模式的一个实际应用示例,也方便大家对比学习和体会,看看如何使用模式来解决问题,以及使用模式的好处。
3. 模式讲解
1)认识某个模式
主要是对模式所涉及的各种知识进行讲述,通常会包含模式的功能、对各部分的理解、对模式实现的探讨、模式运行的顺序等等。
2)针对各个重点难点功能、或是与实际应用结合的讨论和示例
针对模式的一些重点难点,或是模式与实际应用结合,来进行深入的讲解和示例。
3)模式的优缺点
讨论模式的优缺点,好让你在实际应用中尽量使用模式的优点,而规避使用模式的缺点。
4)思考模式
先总结模式的本质,再从设计上思考模式,然后给出适合使用模式的情况。
5)相关模式
描述与其它模式的关系,以及与其它模式相比较的异同点。