<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta name="generator" content="pdf2htmlEX">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<link rel="stylesheet" href="https://static.pudn.com/base/css/base.min.css">
<link rel="stylesheet" href="https://static.pudn.com/base/css/fancy.min.css">
<link rel="stylesheet" href="https://static.pudn.com/prod/directory_preview_static/6246668862b5053d3c1af612/raw.css">
<script src="https://static.pudn.com/base/js/compatibility.min.js"></script>
<script src="https://static.pudn.com/base/js/pdf2htmlEX.min.js"></script>
<script>
try{
pdf2htmlEX.defaultViewer = new pdf2htmlEX.Viewer({});
}catch(e){}
</script>
<title></title>
</head>
<body>
<div id="sidebar" style="display: none">
<div id="outline">
</div>
</div>
<div id="pf1" class="pf w0 h0" data-page-no="1"><div class="pc pc1 w0 h0"><img class="bi x0 y0 w1 h1" alt="" src="https://static.pudn.com/prod/directory_preview_static/6246668862b5053d3c1af612/bg1.jpg"><div class="t m0 x1 h2 y1 ff1 fs0 fc0 sc0 ls0 ws0">下载</div><div class="t m0 x2 h3 y2 ff2 fs1 fc1 sc0 ls0 ws0">第<span class="ff3">1</span>章<span class="_ _0"> </span>引<span class="_ _1"> </span>言</div><div class="t m0 x3 h4 y3 ff4 fs2 fc0 sc0 ls1 ws0">设计面向对象软件比较困难,而设计<span class="_ _2"></span><span class="ff5 ls0">可复用<span class="_ _3"></span></span><span class="ls2">的面向对象软件就更加困难。你必须找到相</span></div><div class="t m0 x4 h4 y4 ff4 fs2 fc0 sc0 ls1 ws0">关的对象,以适当的粒度将它们归类,再定义类的接口和继承层次,建立对象之间的基本关</div><div class="t m0 x4 h4 y5 ff4 fs2 fc0 sc0 ls3 ws0">系。你的设计应该对手头的问题有针对性,同时对将来的问题和需求也要有足够的通用性。</div><div class="t m0 x4 h4 y6 ff4 fs2 fc0 sc0 ls1 ws0">你也希望避免重复设计或尽可能少做重复设计。有经验的面向对象设计者会告诉你,要一下</div><div class="t m0 x4 h4 y7 ff4 fs2 fc0 sc0 ls1 ws0">子就得到复用性和灵活性好的设计,即使不是不可能的至少也是非常困难的。一个设计在最</div><div class="t m0 x4 h4 y8 ff4 fs2 fc0 sc0 ls4 ws0">终完成之前常要被复用好几次,而且每一次都有所修改。</div><div class="t m0 x3 h4 y9 ff4 fs2 fc0 sc0 ls5 ws0">有经验的面向对象设计者的确能做出良好的设计,而新手则面对众多选择无从下手,总</div><div class="t m0 x4 h4 ya ff4 fs2 fc0 sc0 ls1 ws0">是求助于以前使用过的非面向对象技术。新手需要花费较长时间领会良好的面向对象设计是</div><div class="t m0 x4 h4 yb ff4 fs2 fc0 sc0 ls6 ws0">怎么回事。有经验的设计者显然知道一些新手所不知道的东西,这又是什么呢?</div><div class="t m0 x3 h4 yc ff4 fs2 fc0 sc0 ls5 ws0">内行的设计者知道:不是解决任何问题都要从头做起。他们更愿意复用以前使用过的解</div><div class="t m0 x4 h4 yd ff4 fs2 fc0 sc0 ls1 ws0">决方案。当找到一个好的解决方案,他们会一遍又一遍地使用。这些经验是他们成为内行的</div><div class="t m0 x4 h5 ye ff4 fs2 fc0 sc0 ls7 ws0">部分原因。因此,你会在许多面向对象系统中看到类和相互通信的对象(<span class="_ _4"> </span><span class="ff6 ls0 ws1">c o m m u n i c a t i n g</span></div><div class="t m0 x4 h5 yf ff6 fs2 fc0 sc0 ls0 ws2">o b j e c t<span class="ff4 ls8 ws0">)的重复模式。这些模式解决特定的设计问题,使面向对象设计更灵活、优雅,最终复</span></div><div class="t m0 x4 h4 y10 ff4 fs2 fc0 sc0 ls9 ws0">用性更好。它们帮助设计者将新的设计建立在以往工作的基础上,复用以往成功的设计方案。</div><div class="t m0 x4 h4 y11 ff4 fs2 fc0 sc0 lsa ws0">一个熟悉这些模式的设计者不需要再去发现它们,而能够立即将它们应用于设计问题中。</div><div class="t m0 x3 h4 y12 ff4 fs2 fc0 sc0 ls5 ws0">以下类比可以帮助说明这一点。小说家和剧本作家很少从头开始设计剧情。他们总是沿</div><div class="t m0 x4 h5 y13 ff4 fs2 fc0 sc0 lsb ws0">袭一些业已存在的模式,像“悲剧性英雄”模式<span class="_ _5"> </span><span class="ff6">(</span><span class="lsc">《麦克白》<span class="_ _6"></span><span class="ls0">、<span class="_ _6"></span><span class="lsd">《哈姆雷特》等<span class="_ _3"></span><span class="ff6">)<span class="_ _2"></span></span><span class="lse">或“浪漫小说”</span></span></span></span></div><div class="t m0 x4 h5 y14 ff4 fs2 fc0 sc0 ls0 ws0">模式<span class="_ _2"></span><span class="ff6">(<span class="_ _2"></span></span><span class="lsf">存在着无数浪漫小说<span class="_ _3"></span><span class="ff6">)<span class="_ _7"></span><span class="ff4 ls10">。同样地,面向对象设计员也沿袭一些模式,像“用对象表示状态”</span></span></span></div><div class="t m0 x4 h5 y15 ff4 fs2 fc0 sc0 ls11 ws0">和“修饰对象以便于你能容易地添加<span class="_ _8"> </span><span class="ff6">/</span><span class="ls12">删除属性”等。一旦懂得了模式,许多设计决策自然而</span></div><div class="t m0 x4 h4 y16 ff4 fs2 fc0 sc0 ls13 ws0">然就产生了。</div><div class="t m0 x3 h4 y17 ff4 fs2 fc0 sc0 ls14 ws0">我们都知道设计经验的重要价值。你曾经多少次有过这种感觉</div><div class="t m1 x5 h6 y17 ff4 fs3 fc0 sc0 ls0 ws0">—</div><div class="t m0 x6 h4 y17 ff4 fs2 fc0 sc0 ls15 ws0">你已经解决过了一个问</div><div class="t m0 x4 h4 y18 ff4 fs2 fc0 sc0 ls1 ws0">题但就是不能确切知道是在什么地方或怎么解决的?如果你能记起以前问题的细节和怎么解</div><div class="t m0 x4 h4 y19 ff4 fs2 fc0 sc0 ls1 ws0">决它的,你就可以复用以前的经验而不需要重新发现它。然而,我们并没有很好记录下可供</div><div class="t m0 x4 h4 y1a ff4 fs2 fc0 sc0 ls16 ws0">他人使用的软件设计经验。</div><div class="t m0 x3 h4 y1b ff4 fs2 fc0 sc0 ls17 ws0">这本书的目的就是将面向对象软件的设计经验作为<span class="_ _2"></span><span class="ff7 ls1">设计模式<span class="_ _2"></span></span><span class="ls18">记录下来。每一个设计模式</span></div><div class="t m0 x4 h4 y1c ff4 fs2 fc0 sc0 ls1 ws0">系统地命名、解释和评价了面向对象系统中一个重要的和重复出现的设计。我们的目标是将</div><div class="t m0 x4 h4 y1d ff4 fs2 fc0 sc0 ls1 ws0">设计经验以人们能够有效利用的形式记录下来。鉴于此目的,我们编写了一些最重要的设计</div><div class="t m0 x4 h4 y1e ff4 fs2 fc0 sc0 ls19 ws0">模式,并以编目分类的形式将它们展现出来。</div><div class="t m0 x3 h4 y1f ff4 fs2 fc0 sc0 ls5 ws0">设计模式使人们可以更加简单方便地复用成功的设计和体系结构。将已证实的技术表述</div><div class="t m0 x4 h4 y20 ff4 fs2 fc0 sc0 ls1 ws0">成设计模式也会使新系统开发者更加容易理解其设计思路。设计模式帮助你做出有利于系统</div><div class="t m0 x4 h4 y21 ff4 fs2 fc0 sc0 ls1 ws0">复用的选择,避免设计损害了系统复用性。通过提供一个显式类和对象作用关系以及它们之</div><div class="t m0 x4 h4 y22 ff4 fs2 fc0 sc0 ls3 ws0">间潜在联系的说明规范,设计模式甚至能够提高已有系统的文档管理和系统维护的有效性。</div><div class="t m0 x4 h4 y23 ff4 fs2 fc0 sc0 ls14 ws0">简而言之,设计模式可以帮助设计者更快更好地完成系统设计。</div><div class="t m0 x3 h4 y24 ff4 fs2 fc0 sc0 ls5 ws0">本书中涉及的设计模式并不描述新的或未经证实的设计,我们只收录那些在不同系统中</div></div><div class="pi" data-data='{"ctm":[1.841248,0.000000,0.000000,1.841248,0.000000,0.000000]}'></div></div>
</body>
</html>
<div id="pf2" class="pf w0 h0" data-page-no="2"><div class="pc pc2 w0 h0"><img class="bi x0 y0 w1 h1" alt="" src="https://static.pudn.com/prod/directory_preview_static/6246668862b5053d3c1af612/bg2.jpg"><div class="t m0 x7 h4 y25 ff4 fs2 fc0 sc0 ls1 ws0">多次使用过的成功设计。这些设计的绝大部分以往并无文档记录,它们或是来源于面向对象</div><div class="t m0 x7 h4 y26 ff4 fs2 fc0 sc0 ls1 ws0">设计者圈子里的非正式交流,或是来源于某些成功的面向对象系统的某些部分,但对设计新</div><div class="t m0 x7 h4 y27 ff4 fs2 fc0 sc0 ls1 ws0">手来说,这些东西是很难学得到的。尽管这些设计不包含新的思路,但我们用一种新的、便</div><div class="t m0 x7 h4 y28 ff4 fs2 fc0 sc0 ls14 ws0">于理解的方式将其展现给读者,即:具有统一格式的、已分类编目<span class="_ _2"></span><span class="ff5 ls0">的若干<span class="_ _2"></span></span><span class="ls13">组设计模式。</span></div><div class="t m0 x8 h4 y29 ff4 fs2 fc0 sc0 ls5 ws0">尽管该书涉及较多的内容,但书中讨论的设计模式仅仅包含了一个设计行家所知道的部</div><div class="t m0 x7 h4 y2a ff4 fs2 fc0 sc0 ls1 ws0">分。书中没有讨论与并发或分布式或实时程序设计有关的模式,也没有收录面向特定应用领</div><div class="t m0 x7 h4 y2b ff4 fs2 fc0 sc0 ls1 ws0">域的模式。本书并不准备告诉你怎样构造用户界面、怎样写设备驱动程序或怎样使用面向对</div><div class="t m0 x7 h4 y2c ff4 fs2 fc0 sc0 ls1a ws0">象数据库,这些方面都有自己的模式,将这些模式分类编目也是件很有意义的事。</div><div class="t m0 x7 h7 y2d ff3 fs4 fc1 sc0 ls0 ws0">1.1 <span class="ff7">什么是设计模式</span></div><div class="t m0 x8 h5 y2e ff6 fs2 fc0 sc0 ls1b ws0">Christopher Alexander<span class="_ _2"></span><span class="ff4 ls0">说过:<span class="_ _9"></span><span class="ls1c">“每一个模式描述了一个在我们周围不断重复发生的问题,</span></span></div><div class="t m0 x7 h4 y2f ff4 fs2 fc0 sc0 ls1d ws0">以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动”</div><div class="t m0 x7 h5 y30 ff6 fs2 fc0 sc0 ls0 ws3">[ A I S + 7 7<span class="_"> </span><span class="ff4 ws0">,第<span class="_ _a"></span></span>1 0<span class="_"> </span><span class="ff4 ws0">页<span class="_ _2"></span><span class="ff6">]</span>。尽管<span class="_ _b"></span></span>A l e x a n d e r<span class="ff4 ls1e ws0">所指的是城市和建筑模式,但他的思想也同样适用于面向</span></div><div class="t m0 x7 h4 y31 ff4 fs2 fc0 sc0 ls1 ws0">对象设计模式,只是在面向对象的解决方案里,我们用对象和接口代替了墙壁和门窗。两类</div><div class="t m0 x7 h4 y32 ff4 fs2 fc0 sc0 ls19 ws0">模式的核心都在于提供了相关问题的解决方案。</div><div class="t m0 x8 h4 y33 ff4 fs2 fc0 sc0 ls1f ws0">一般而言,一个模式有四个基本要素:</div><div class="t m0 x8 h5 y34 ff3 fs2 fc0 sc0 ls0 ws0">1. <span class="_ _c"> </span><span class="ff7">模式名称<span class="_ _a"></span><span class="ff4">(<span class="_ _2"></span><span class="ff6 ls20">pattern name</span>)<span class="_ _d"> </span><span class="ls21">一个助记名,它用一两个词来描述模式的问题、解决方案</span></span></span></div><div class="t m0 x7 h4 y35 ff4 fs2 fc0 sc0 ls1 ws0">和效果。命名一个新的模式增加了我们的设计词汇。设计模式允许我们在较高的抽象层次上</div><div class="t m0 x7 h4 y36 ff4 fs2 fc0 sc0 ls1 ws0">进行设计。基于一个模式词汇表,我们自己以及同事之间就可以讨论模式并在编写文档时使</div><div class="t m0 x7 h4 y37 ff4 fs2 fc0 sc0 ls1 ws0">用它们。模式名可以帮助我们思考,便于我们与其他人交流设计思想及设计结果。找到恰当</div><div class="t m0 x7 h4 y38 ff4 fs2 fc0 sc0 ls22 ws0">的模式名也是我们设计模式编目工作的难点之一。</div><div class="t m0 x8 h5 y39 ff3 fs2 fc0 sc0 ls0 ws0">2. <span class="_ _e"> </span><span class="ff7">问题<span class="_ _2"></span><span class="ff6 ls23">(problem) <span class="_ _3"></span><span class="ff4 lsc">描述了应该在何时使用模式。它解释了设计问题和问题存在的前因后</span></span></span></div><div class="t m0 x7 h4 y3a ff4 fs2 fc0 sc0 ls1 ws0">果,它可能描述了特定的设计问题,如怎样用对象表示算法等。也可能描述了导致不灵活设</div><div class="t m0 x7 h4 y3b ff4 fs2 fc0 sc0 ls1a ws0">计的类或对象结构。有时候,问题部分会包括使用模式必须满足的一系列先决条件。</div><div class="t m0 x8 h5 y3c ff3 fs2 fc0 sc0 ls0 ws0">3. <span class="_ _e"> </span><span class="ff7">解决方案<span class="_ _a"></span><span class="ff6 ls24">(solution) <span class="_ _3"></span><span class="ff4 ls25">描述了设计的组成成分,它们之间的相互关系及各自的职责和协</span></span></span></div><div class="t m0 x7 h4 y3d ff4 fs2 fc0 sc0 ls1 ws0">作方式。因为模式就像一个模板,可应用于多种不同场合,所以解决方案并不描述一个特定</div><div class="t m0 x7 h4 y3e ff4 fs2 fc0 sc0 ls1 ws0">而具体的设计或实现,而是提供设计问题的抽象描述和怎样用一个具有一般意义的元素组合</div><div class="t m0 x9 h4 y3f ff4 fs2 fc0 sc0 ls26 ws0">(类或对象组合)来解决这个问题。</div><div class="t m0 x8 h5 y40 ff3 fs2 fc0 sc0 ls0 ws0">4. <span class="_ _c"> </span><span class="ff7">效果<span class="_ _2"></span><span class="ff6 ls27">(consequences) <span class="_ _3"></span><span class="ff4 ls28">描述了模式应用的效果及使用模式应权衡的问题。尽管我们描述</span></span></span></div><div class="t m0 x7 h4 y41 ff4 fs2 fc0 sc0 ls1 ws0">设计决策时,并不总提到模式效果,但它们对于评价设计选择和理解使用模式的代价及好处</div><div class="t m0 x7 h4 y42 ff4 fs2 fc0 sc0 ls1 ws0">具有重要意义。软件效果大多关注对时间和空间的衡量,它们也表述了语言和实现问题。因</div><div class="t m0 x7 h4 y43 ff4 fs2 fc0 sc0 ls1 ws0">为复用是面向对象设计的要素之一,所以模式效果包括它对系统的灵活性、扩充性或可移植</div><div class="t m0 x7 h4 y44 ff4 fs2 fc0 sc0 ls14 ws0">性的影响,显式地列出这些效果对理解和评价这些模式很有帮助。</div><div class="t m0 x8 h4 y45 ff4 fs2 fc0 sc0 ls5 ws0">出发点的不同会产生对什么是模式和什么不是模式的理解不同。一个人的模式对另一个</div><div class="t m0 x7 h4 y46 ff4 fs2 fc0 sc0 ls29 ws0">人来说可能只是基本构造部件。本书中我们将在一定的抽象层次上讨论模式。<span class="_ _6"></span><span class="ls2a">《设计模式》并</span></div><div class="t m0 x7 h5 y47 ff4 fs2 fc0 sc0 ls13 ws0">不描述链表和<span class="_ _c"> </span><span class="ff6 ls0 ws4">h a s h</span><span class="ls2b">表那样的设计,尽管它们可以用类来封装,也可复用;也不包括那些复杂</span></div><div class="t m0 x7 h4 y48 ff4 fs2 fc0 sc0 ls2c ws0">的、特定领域内的对整个应用或子系统的设计。本书中的设计模式是<span class="_ _2"></span><span class="ff5 ls2d">对被用来在特定场景下</span></div><div class="t m0 x7 h4 y49 ff5 fs2 fc0 sc0 ls19 ws0">解决一般设计问题的类和相互通信的对象的描述<span class="_ _2"></span><span class="ff4 ls0">。</span></div><div class="t m0 x8 h4 y4a ff4 fs2 fc0 sc0 ls5 ws0">一个设计模式命名、抽象和确定了一个通用设计结构的主要方面,这些设计结构能被用</div><div class="t m0 xa h8 y4b ff8 fs5 fc2 sc0 ls5 ws0">2<span class="_ _f"> </span><span class="ff9 fs2 fc0 ls0">设计模式<span class="_ _a"></span><span class="ffa">:</span><span class="ls2e">可复用面向对象软件的基础</span></span></div><div class="t m0 xb h2 y1 ff1 fs0 fc0 sc0 ls0 ws0">下载</div></div><div class="pi" data-data='{"ctm":[1.841248,0.000000,0.000000,1.841248,0.000000,0.000000]}'></div></div>
<div id="pf3" class="pf w0 h0" data-page-no="3"><div class="pc pc3 w0 h0"><img class="bi x0 y0 w1 h1" alt="" src="https://static.pudn.com/prod/directory_preview_static/6246668862b5053d3c1af612/bg3.jpg"><div class="t m0 x4 h4 y25 ff4 fs2 fc0 sc0 ls1 ws0">来构造可复用的面向对象设计。设计模式确定了所包含的类和实例,它们的角色、协作方式</div><div class="t m0 x4 h4 y26 ff4 fs2 fc0 sc0 ls1 ws0">以及职责分配。每一个设计模式都集中于一个特定的面向对象设计问题或设计要点,描述了</div><div class="t m0 x4 h4 y27 ff4 fs2 fc0 sc0 ls1 ws0">什么时候使用它,在另一些设计约束条件下是否还能使用,以及使用的效果和如何取舍。既</div><div class="t m0 x4 h5 y28 ff4 fs2 fc0 sc0 ls1f ws0">然我们最终要实现设计,设计模式还提供了<span class="_ _e"> </span><span class="ff6 ls0">C++ <span class="_ _a"></span><span class="ff4">和<span class="_ _2"></span></span><span class="ws5">S m a l l t a l k</span></span><span class="ls2f">示例代码来阐明其实现。</span></div><div class="t m0 x3 h4 y29 ff4 fs2 fc0 sc0 ls5 ws0">虽然设计模式描述的是面向对象设计,但它们都基于实际的解决方案,这些方案的实现</div><div class="t m0 x4 h5 y2a ff4 fs2 fc0 sc0 ls0 ws0">语言是<span class="_ _a"></span><span class="ff6 ls2a">Smalltalk </span>和<span class="_ _2"></span><span class="ff6 ws5">C + +</span><span class="ls22">等主流面向对象编程语言,而不是过程式语言<span class="_ _e"> </span></span><span class="ff6 ws5">( P a s c a l<span class="_"> </span></span>、<span class="_ _2"></span><span class="ff6">C</span>、<span class="ff6 ws5">A d a )<span class="_"> </span></span>或更具</div><div class="t m0 x4 h5 y2b ff4 fs2 fc0 sc0 ls30 ws0">动态特性的面向对象语言<span class="_ _3"></span><span class="ff6 ls0 ws5">( C L O S<span class="_"> </span></span><span class="ls0">、<span class="_ _7"></span><span class="ff6 ws5">D y l a n<span class="ff4 ws0">、<span class="_ _10"></span><span class="ff6 ws5">S e l f )<span class="ff4 ls31 ws0">。我们从实用角度出发选择了<span class="_ _3"></span><span class="ff6 ls2a">Smalltalk </span><span class="ls0">和<span class="_ _2"></span></span></span>C + +<span class="ff4 ws0">,</span></span></span></span></span></div><div class="t m0 x4 h4 y2c ff4 fs2 fc0 sc0 ls6 ws0">因为在这些语言的使用上,我们积累了许多经验,况且它们也变得越来越流行。</div><div class="t m0 x3 h4 y4c ff4 fs2 fc0 sc0 ls32 ws0">程序设计语言的选择非常重要,它将影响人们理解问题的出发点。我们的设计模式采用了</div><div class="t m0 x4 h5 y4d ff6 fs2 fc0 sc0 ls33 ws0">Smalltalk <span class="_ _3"></span><span class="ff4 ls0">和<span class="_ _2"></span><span class="ff6 ws6">C + +</span><span class="ls34">层的语言特性,这个选择实际上决定了哪些机制可以方便地实现,而哪些则</span></span></div><div class="t m0 x4 h4 y4e ff4 fs2 fc0 sc0 ls35 ws0">不能。若我们采用过程式语言,可能就要包括诸如“继承”<span class="_ _6"></span><span class="ls0">、<span class="_ _6"></span><span class="ls36">“封装”和“多态”的设计模式。</span></span></div><div class="t m0 x4 h5 y4f ff4 fs2 fc0 sc0 ls37 ws0">相应地,一些特殊的面向对象语言可以直接支持我们的某些模式,例如:<span class="_ _11"> </span><span class="ff6 ls0 ws7">C L O S<span class="_"> </span></span><span class="ls38">支持多方法</span></div><div class="t m0 xc h5 y50 ff4 fs2 fc0 sc0 ls0 ws0">(<span class="_ _2"></span><span class="ff6 ws8">m u l t i - m e t h o d</span><span class="ls39">)概念,这就减少了<span class="_ _b"></span><span class="ff6">V<span class="_ _7"></span><span class="ls0 ws8">i s i t o r<span class="_"> </span><span class="ff4 ls30 ws0">模式的必要性。事实上,<span class="_ _3"> </span></span>S m a l l t a l k<span class="ff4 ws0">和<span class="_ _2"></span></span>C + +<span class="ff4 ws0">已有足够的</span></span></span></span></div><div class="t m0 x4 h5 y51 ff4 fs2 fc0 sc0 ls3a ws0">差别来说明对某些模式一种语言比另一种语言表述起来更容易一些<span class="_ _12"> </span><span class="ff6">(</span><span class="ls0">参见<span class="_ _2"></span><span class="ws9">5 . 4<span class="_ _2"></span></span>节<span class="ff6 ls3b">Iterator <span class="_ _2"></span></span>模式<span class="ff6">)<span class="_ _2"></span></span>。</span></div><div class="t m0 x4 h7 y52 ff3 fs4 fc1 sc0 ls0 ws0">1.2 Smalltalk MVC<span class="ff7">中的设计模式</span></div><div class="t m0 x3 h5 y34 ff4 fs2 fc0 sc0 ls0 ws0">在<span class="_ _2"></span><span class="ff6 wsa">S m a l l t a l k - 8 0</span><span class="ls39">中,类的模型<span class="_ _a"></span><span class="ff6">/<span class="_ _2"></span></span></span>视图<span class="_ _2"></span><span class="ff6">/</span>控制器(<span class="_ _b"></span><span class="ff6 wsb">M o d e l / Vi e w / C o n t r o l l e r<span class="_"> </span></span>)三元组<span class="_ _a"></span><span class="ff6 wsa">( M V C )<span class="_ _2"></span></span>被用来</div><div class="t m0 x4 h5 y35 ff4 fs2 fc0 sc0 lsf ws0">构建用户界面。透过<span class="_ _b"></span><span class="ff6 ls0">MVC <span class="_ _a"></span></span><span class="ls3c">来看设计模式将帮助我们理解“模式”这一术语的含义。</span></div><div class="t m0 x3 h5 y36 ff6 fs2 fc0 sc0 ls0 wsc">M V C<span class="_"> </span><span class="ff4 ls3d ws0">包括三类对象。模型<span class="_ _12"> </span></span>M o d e l<span class="_ _a"></span><span class="ff4 ls3e ws0">是应用对象,视图<span class="_ _8"> </span><span class="ff6">V<span class="_ _7"></span><span class="ls0 wsc">i e w<span class="_"> </span><span class="ff4 ls3f ws0">是它在屏幕上的表示,控制器</span></span></span></span></div><div class="t m0 x4 h5 y37 ff6 fs2 fc0 sc0 ls0 wsd">C o n t r o l l e r<span class="_"> </span><span class="ff4 ls40 ws0">定义用户界面对用户输入的响应方式。不使用<span class="_ _8"> </span></span>M V C<span class="ff4 ls41 ws0">,用户界面设计往往将这些对象</span></div><div class="t m0 x4 h5 y38 ff4 fs2 fc0 sc0 ls42 ws0">混在一起,而<span class="_ _a"></span><span class="ff6 ls0 ws5">M V C</span><span class="ls1f">则将它们分离以提高灵活性和复用性。</span></div><div class="t m0 x3 h5 y39 ff6 fs2 fc0 sc0 ls0 wse">M V C<span class="_"> </span><span class="ff4 ls43 ws0">通过建立一个“订购<span class="_ _3"> </span><span class="ff6">/</span><span class="ls8">通知”协议来分离视图和模型。视图必须保证它的显示正确地</span></span></div><div class="t m0 x4 h4 y3a ff4 fs2 fc0 sc0 ls1 ws0">反映了模型的状态。一旦模型的数据发生变化,模型将通知有关的视图,每个视图相应地得</div><div class="t m0 x4 h4 y3b ff4 fs2 fc0 sc0 ls1 ws0">到刷新自己的机会。这种方法可以让你为一个模型提供不同的多个视图表现形式,也能够为</div><div class="t m0 x4 h4 y3c ff4 fs2 fc0 sc0 ls44 ws0">一个模型创建新的视图而无须重写模型。</div><div class="t m0 x3 h4 y3d ff4 fs2 fc0 sc0 ls45 ws0">下图显示了一个模型和三个视图(为了简单起见我们省略了控制器)<span class="_ _6"></span><span class="ls46">。模型包含一些数据</span></div><div class="t m0 x4 h4 y3e ff4 fs2 fc0 sc0 ls1 ws0">值,视图通过电子表格、柱状图、饼图这些不同的方式来显示这些数据。当模型的数据发生</div><div class="t m0 x4 h4 y3f ff4 fs2 fc0 sc0 ls47 ws0">变化时,模型就通知它的视图,而视图将与模型通信以访问这些数据值。</div><div class="t m0 xd h8 y4b ff9 fs2 fc0 sc0 ls0 ws0">第<span class="ffb">1<span class="_ _2"></span></span>章<span class="_ _13"> </span>引<span class="_ _f"> </span>言<span class="_ _f"> </span><span class="ff8 fs5 fc2">3</span></div><div class="t m0 x1 h2 y1 ff1 fs0 fc0 sc0 ls0 ws0">下载</div><div class="t m0 xe h9 y53 ff4 fs6 fc0 sc0 ls0 ws0">视图</div><div class="t m0 xf h9 y54 ff4 fs6 fc0 sc0 ls0 ws0">模型</div></div><div class="pi" data-data='{"ctm":[1.841248,0.000000,0.000000,1.841248,0.000000,0.000000]}'></div></div>
<div id="pf4" class="pf w0 h0" data-page-no="4"><div class="pc pc4 w0 h0"><img class="bi x0 y0 w1 h1" alt="" src="https://static.pudn.com/prod/directory_preview_static/6246668862b5053d3c1af612/bg4.jpg"><div class="t m0 x8 h4 y25 ff4 fs2 fc0 sc0 ls5 ws0">表面上看,这个例子反映了将视图和模型分离的设计,然而这个设计还可用于解决更一</div><div class="t m0 x7 h4 y26 ff4 fs2 fc0 sc0 ls1 ws0">般的问题:将对象分离,使得一个对象的改变能够影响另一些对象,而这个对象并不需要知</div><div class="t m0 x7 h5 y27 ff4 fs2 fc0 sc0 ls3c ws0">道那些被影响的对象的细节。这个更一般的设计被描述成<span class="_ _8"> </span><span class="ff6 ls0 ws5">O b s e r v e r<span class="_ _2"></span></span><span class="ls0">(<span class="_ _2"></span><span class="ff6 ws5">5 . 7</span>)模式。</span></div><div class="t m0 x8 h5 y28 ff6 fs2 fc0 sc0 ls0 wsf">M V C<span class="_"> </span><span class="ff4 ls2d ws0">的另一个特征是视图可以嵌套。例如,按钮控制面板可以用一个嵌套了按钮的复杂</span></div><div class="t m0 x7 h4 y29 ff4 fs2 fc0 sc0 ls48 ws0">视图来实现。对象查看器的用户界面可由嵌套的视图构成,这些视图又可复用于调试器。</div><div class="t m0 x7 h5 y2a ff6 fs2 fc0 sc0 ls0 ws10">M V C<span class="_"> </span><span class="ff4 ws0">用<span class="_ _2"></span><span class="ff6">V<span class="_ _7"></span><span class="ws10">i e w<span class="_"> </span><span class="ff4 ws0">类的子类</span></span></span></span></div><div class="t m1 x10 h6 y2a ff4 fs3 fc0 sc0 ls0 ws0">—</div><div class="t m0 x11 h5 y2a ff6 fs2 fc0 sc0 ls0 ws11">C o m p o s i t e Vi e w<span class="ff4 ls43 ws0">类来支持嵌套视图。<span class="_ _3"> </span></span><span class="ws10">C o m p o s i t e Vi e w<span class="ff4 ls2a ws0">类的对象行为上</span></span></div><div class="t m0 x7 h5 y2b ff4 fs2 fc0 sc0 ls0 ws0">类似于<span class="_ _a"></span><span class="ff6">V<span class="ws5">i e w</span></span><span class="ls44">类对象,一个组合视图可用于任何视图可用的地方,但是它包含并管理嵌套视图。</span></div><div class="t m0 x8 h4 y2c ff4 fs2 fc0 sc0 ls5 ws0">上例反映了可以将组合视图与其构件平等对待的设计,同样地,该设计也适用于更一般</div><div class="t m0 x7 h4 y4c ff4 fs2 fc0 sc0 ls49 ws0">的问题:将一些对象划为一组,并将该组对象当作一个对象来使用。这个设计被描述为</div><div class="t m0 x7 h5 y4d ff6 fs2 fc0 sc0 ls0 ws12">C o m p o s i t e<span class="_"> </span><span class="ff4 ws0">(<span class="_ _2"></span></span>4 . 3<span class="_"> </span><span class="ff4 ls4a ws0">)模式,该模式允许你创建一个类层次结构,一些子类定义了原子对象(如</span></div><div class="t m0 x7 h5 y4e ff6 fs2 fc0 sc0 ls0 ws13">B u t t o n<span class="_ _a"></span><span class="ff4 ls4b ws0">)而其他类定义了组合对象(<span class="_ _12"> </span></span><span class="ws14">C o m p o s i t e Vi e w<span class="_"> </span><span class="ff4 ws0">)<span class="_ _6"></span><span class="ls4c">,这些组合对象是由原子对象组合而成</span></span></span></div><div class="t m0 x7 h4 y4f ff4 fs2 fc0 sc0 ls4d ws0">的更复杂的对象。</div><div class="t m0 x8 h5 y50 ff6 fs2 fc0 sc0 ls0 wsf">M V C<span class="_"> </span><span class="ff4 ls2d ws0">允许你在不改变视图外观的情况下改变视图对用户输入的响应方式。例如,你可能</span></div><div class="t m0 x7 h5 y51 ff4 fs2 fc0 sc0 ls4e ws0">希望改变视图对键盘的响应方式,或希望使用弹出菜单而不是原来的命令键方式。<span class="_ _14"> </span><span class="ff6 ls0 ws15">M V C<span class="_"> </span></span><span class="ls0">将响</span></div><div class="t m0 x7 h5 y55 ff4 fs2 fc0 sc0 ls39 ws0">应机制封装在<span class="_ _b"></span><span class="ff6 ls0 ws16">C o n t r o l l e r<span class="_"> </span></span><span class="ls43">对象中。存在着一个<span class="_ _3"></span><span class="ff6 ls0 ws16">C o n t r o l l e r<span class="_"> </span></span><span class="ls4f">的类层次结构,使得可以方便地对原有</span></span></div><div class="t m0 x7 h5 y56 ff6 fs2 fc0 sc0 ls0 ws5">C o n t r o l l e r<span class="ff4 ls50 ws0">做适当改变而创建新的<span class="_ _3"> </span></span>C o n t r o l l e r<span class="_"> </span><span class="ff4 ws0">。</span></div><div class="t m0 x8 h5 y57 ff6 fs2 fc0 sc0 ls0 ws0">V<span class="ws17">i e w<span class="_"> </span></span><span class="ff4">使用<span class="_ _2"></span></span><span class="ws17">C o n t r o l l e r<span class="_"> </span></span><span class="ff4 ls51">子类的实例来实现一个特定的响应策略。要实现不同的响应策略只要</span></div><div class="t m0 x7 h5 y58 ff4 fs2 fc0 sc0 ls39 ws0">用不同种类的<span class="_ _a"></span><span class="ff6 ls0 ws18">C o n t r o l l e r<span class="_"> </span></span>实例替换即可。甚至可以在运行时刻通过改变<span class="_ _12"> </span><span class="ff6">V<span class="_ _10"></span><span class="ls0 ws18">i e w<span class="_"> </span><span class="ff4 ws0">的<span class="_ _2"></span></span>C o n t r o l l e r<span class="ff4 ws0">来改变</span></span></span></div><div class="t m0 x7 h5 y59 ff6 fs2 fc0 sc0 ls0 ws0">V<span class="ws19">i e w</span><span class="ff4 ls11">对用户输入的响应方式。例如,一个<span class="_ _12"> </span><span class="ff6">V<span class="_ _7"></span><span class="ls0 ws19">i e w<span class="_"> </span><span class="ff4 ls52 ws0">可以被禁止接收任何输入,只需给它一个忽略</span></span></span></span></div><div class="t m0 x7 h5 y5a ff4 fs2 fc0 sc0 ls0 ws0">输入事件的<span class="_ _b"></span><span class="ff6 ws5">C o n t r o l l e r<span class="_"> </span></span>。</div><div class="t m0 x8 h5 y5b ff6 fs2 fc0 sc0 ls0 ws0">V<span class="_ _10"></span><span class="ws5">i e w - C o n t r o l l e r<span class="_ _2"></span><span class="ff4 ws0">关系是<span class="_ _a"></span></span>S t r a t e g y<span class="ff4 ws0">(</span>5 . 9<span class="_"> </span><span class="ff4 ls53 ws0">)模式的一个例子。一个策略是一个表述算法的对象。</span></span></div><div class="t m0 x7 h4 y5c ff4 fs2 fc0 sc0 ls1 ws0">当你想静态或动态地替换一个算法,或你有很多不同的算法,或算法中包含你想封装的复杂</div><div class="t m0 x7 h4 y5d ff4 fs2 fc0 sc0 ls1f ws0">数据结构,这时策略模式是非常有用的。</div><div class="t m0 x8 h5 y5e ff6 fs2 fc0 sc0 ls0 ws1a">M V C<span class="_"> </span><span class="ff4 ls54 ws0">还使用了其他的设计模式,如:用来指定视图缺省控制器的<span class="_ _15"> </span><span class="ff6 ls5">Factory Method(3.3)<span class="_ _2"></span></span><span class="ls0">和</span></span></div><div class="t m0 x7 h5 y5f ff4 fs2 fc0 sc0 ls55 ws0">用来增加视图滚动的<span class="_ _8"> </span><span class="ff6 ls0 ws1b">D e c o r a t o r ( 4 . 4 )<span class="_"> </span></span><span class="ls13">。但是<span class="_ _a"></span><span class="ff6 ls0 ws1b">M V C<span class="_ _a"></span></span><span class="ls1d">的主要关系还是由<span class="_ _12"> </span><span class="ff6 ls0 ws1b">O b s e r v e r<span class="_"> </span></span><span class="ls0">、<span class="_ _a"></span><span class="ff6 ws1b">C o m p o s i t e<span class="_ _2"></span></span>和</span></span></span></div><div class="t m0 x7 h5 y60 ff6 fs2 fc0 sc0 ls0 ws5">S t r a t e g y<span class="_"> </span><span class="ff4 ls50 ws0">三个设计模式给出的。</span></div><div class="t m0 x7 h7 y61 ff3 fs4 fc1 sc0 ls0 ws0">1.3 <span class="ff7">描述设计模式</span></div><div class="t m0 x8 h4 y40 ff4 fs2 fc0 sc0 ls5 ws0">我们怎样描述设计模式呢?图形符号虽然很重要也很有用,却还远远不够,它们只是将</div><div class="t m0 x7 h4 y41 ff4 fs2 fc0 sc0 ls1 ws0">设计过程的结果简单记录为类和对象之间的关系。为了达到设计复用,我们必须同时记录设</div><div class="t m0 x7 h4 y42 ff4 fs2 fc0 sc0 ls1 ws0">计产生的决定过程、选择过程和权衡过程。具体的例子也是很重要的,它们让你看到实际的</div><div class="t m0 x7 h4 y43 ff4 fs2 fc0 sc0 ls0 ws0">设计。</div><div class="t m0 x8 h4 y44 ff4 fs2 fc0 sc0 ls5 ws0">我们将用统一的格式描述设计模式,每一个模式根据以下的模板被分成若干部分。模板</div><div class="t m0 x7 h4 y45 ff4 fs2 fc0 sc0 ls47 ws0">具有统一的信息描述结构,有助于你更容易地学习、比较和使用设计模式。</div><div class="t m0 x8 h4 y46 ff7 fs2 fc0 sc0 ls13 ws0">模式名和分类</div><div class="t m0 x8 h4 y47 ff4 fs2 fc0 sc0 ls5 ws0">模式名简洁地描述了模式的本质。一个好的名字非常重要,因为它将成为你的设计词汇</div><div class="t m0 x7 h5 y48 ff4 fs2 fc0 sc0 ls1f ws0">表中的一部分。模式的分类反映了我们将在<span class="_ _e"> </span><span class="ff6 ls0 ws5">1 . 5<span class="_"> </span></span><span class="ls56">节介绍的方案。</span></div><div class="t m0 x8 h4 y49 ff7 fs2 fc0 sc0 ls0 ws0">意图</div><div class="t m0 x8 h4 y4a ff4 fs2 fc0 sc0 ls5 ws0">是回答下列问题的简单陈述:设计模式是做什么的?它的基本原理和意图是什么?它解</div><div class="t m0 xa h8 y4b ff8 fs5 fc2 sc0 ls5 ws0">4<span class="_ _f"> </span><span class="ff9 fs2 fc0 ls0">设计模式<span class="_ _a"></span><span class="ffa">:</span><span class="ls2e">可复用面向对象软件的基础</span></span></div><div class="t m0 xb h2 y1 ff1 fs0 fc0 sc0 ls0 ws0">下载</div></div><div class="pi" data-data='{"ctm":[1.841248,0.000000,0.000000,1.841248,0.000000,0.000000]}'></div></div>
<div id="pf5" class="pf w0 h0" data-page-no="5"><div class="pc pc5 w0 h0"><img class="bi x0 y0 w1 h1" alt="" src="https://static.pudn.com/prod/directory_preview_static/6246668862b5053d3c1af612/bg5.jpg"><div class="t m0 x4 h4 y25 ff4 fs2 fc0 sc0 ls28 ws0">决的是什么样的特定设计问题?</div><div class="t m0 x3 h4 y26 ff7 fs2 fc0 sc0 ls0 ws0">别名</div><div class="t m0 x3 h4 y27 ff4 fs2 fc0 sc0 ls57 ws0">模式的其他名称。</div><div class="t m0 x3 h4 y28 ff7 fs2 fc0 sc0 ls0 ws0">动机</div><div class="t m0 x3 h4 y29 ff4 fs2 fc0 sc0 ls5 ws0">用以说明一个设计问题以及如何用模式中的类、对象来解决该问题的特定情景。该情景</div><div class="t m0 x4 h4 y2a ff4 fs2 fc0 sc0 ls44 ws0">会帮助你理解随后对模式更抽象的描述。</div><div class="t m0 x3 h4 y2b ff7 fs2 fc0 sc0 ls0 ws0">适用性</div><div class="t m0 x3 h4 y2c ff4 fs2 fc0 sc0 ls5 ws0">什么情况下可以使用该设计模式?该模式可用来改进哪些不良设计?你怎样识别这些情</div><div class="t m0 x4 h4 y4c ff4 fs2 fc0 sc0 ls0 ws0">况?</div><div class="t m0 x3 h4 y4d ff7 fs2 fc0 sc0 ls0 ws0">结构</div><div class="t m0 x3 h5 y4e ff4 fs2 fc0 sc0 ls58 ws0">采用基于对象建模技术(<span class="_ _c"> </span><span class="ff6 ls0 ws1c">O M T<span class="_"> </span></span><span class="ls0">)<span class="_ _2"></span><span class="ff6 ws1c">[ R B P + 9 1 ]<span class="_"> </span></span><span class="ls20">的表示法对模式中的类进行图形描述。我们也</span></span></div><div class="t m0 x4 h5 y4f ff4 fs2 fc0 sc0 ls13 ws0">使用了交互图<span class="_ _c"> </span><span class="ff6 ls0 ws1d">[ J C J O 9 2</span><span class="ls0">,<span class="_ _2"></span><span class="ff6 ws1d">B O O 9 4 ]<span class="_"> </span></span><span class="ls15">来说明对象之间的请求序列和协作关系。附录<span class="_ _16"> </span><span class="ff6">B<span class="_ _2"></span></span><span class="ls33">详细描述了</span></span></span></div><div class="t m0 x4 h4 y50 ff4 fs2 fc0 sc0 ls13 ws0">这些表示法。</div><div class="t m0 x3 h4 y51 ff7 fs2 fc0 sc0 ls0 ws0">参与者</div><div class="t m0 x3 h5 y55 ff4 fs2 fc0 sc0 lsf ws0">指设计模式中的类和<span class="_ _b"></span><span class="ff6">/</span><span class="ls4a">或对象以及它们各自的职责。</span></div><div class="t m0 x3 h4 y56 ff7 fs2 fc0 sc0 ls0 ws0">协作</div><div class="t m0 x3 h4 y57 ff4 fs2 fc0 sc0 ls59 ws0">模式的参与者怎样协作以实现它们的职责。</div><div class="t m0 x3 h4 y58 ff7 fs2 fc0 sc0 ls0 ws0">效果</div><div class="t m0 x3 h4 y59 ff4 fs2 fc0 sc0 ls5 ws0">模式怎样支持它的目标?使用模式的效果和所需做的权衡取舍?系统结构的哪些方面可</div><div class="t m0 x4 h4 y5a ff4 fs2 fc0 sc0 ls13 ws0">以独立改变?</div><div class="t m0 x3 h4 y5b ff7 fs2 fc0 sc0 ls0 ws0">实现</div><div class="t m0 x3 h4 y5c ff4 fs2 fc0 sc0 ls5 ws0">实现模式时需要知道的一些提示、技术要点及应避免的缺陷,以及是否存在某些特定于</div><div class="t m0 x4 h4 y5d ff4 fs2 fc0 sc0 ls57 ws0">实现语言的问题。</div><div class="t m0 x3 h4 y5e ff7 fs2 fc0 sc0 ls0 ws0">代码示例</div><div class="t m0 x3 h5 y5f ff4 fs2 fc0 sc0 ls5a ws0">用来说明怎样用<span class="_ _a"></span><span class="ff6 ls0 ws5">C + +<span class="_"> </span></span><span class="ls0">或<span class="_ _2"></span><span class="ff6 ws5">S m a l l t a l k</span><span class="ls2f">实现该模式的代码片段。</span></span></div><div class="t m0 x3 h4 y60 ff7 fs2 fc0 sc0 ls0 ws0">已知应用</div><div class="t m0 x3 h4 y62 ff4 fs2 fc0 sc0 ls5b ws0">实际系统中发现的模式的例子。每个模式至少包括了两个不同领域的实例。</div><div class="t m0 x3 h4 y63 ff7 fs2 fc0 sc0 ls0 ws0">相关模式</div><div class="t m0 x3 h4 y64 ff4 fs2 fc0 sc0 ls5 ws0">与这个模式紧密相关的模式有哪些?其间重要的不同之处是什么?这个模式应与哪些其</div><div class="t m0 x4 h4 y65 ff4 fs2 fc0 sc0 ls57 ws0">他模式一起使用?</div><div class="t m0 x3 h5 y66 ff4 fs2 fc0 sc0 ls5c ws0">附录提供的背景资料将帮助你理解模式以及关于模式的讨论。附录<span class="_ _5"> </span><span class="ff6">A</span><span class="ls5d">给出了我们使用的术</span></div><div class="t m0 x4 h5 y67 ff4 fs2 fc0 sc0 ls39 ws0">语列表。前面已经提到过的附录<span class="_ _c"> </span><span class="ff6">B<span class="_ _2"></span></span><span class="ls5e">则给出了各种表示法,我们也会在以后的讨论中简单介绍它</span></div><div class="t m0 x4 h5 y68 ff4 fs2 fc0 sc0 ls5a ws0">们。最后,附录<span class="_ _a"></span><span class="ff6">C<span class="_ _2"></span></span><span class="ls22">给出了我们在例子中使用的各基本类的源代码。</span></div><div class="t m0 x4 h7 y69 ff3 fs4 fc1 sc0 ls0 ws0">1.4 <span class="ff7">设计模式的编目</span></div><div class="t m0 x3 h5 y47 ff4 fs2 fc0 sc0 ls0 ws0">从第<span class="_ _2"></span><span class="ff6">3<span class="_ _2"></span></span><span class="ls5f">章开始的模式目录中共包含<span class="_ _c"> </span></span><span class="ff6 ws1e">2 3<span class="_"> </span></span><span class="ls25">个设计模式。它们的名字和意图列举如下,以使你有</span></div><div class="t m0 x4 h5 y48 ff4 fs2 fc0 sc0 ls3c ws0">个基本了解。每个模式名后括号中标出模式所在的章节<span class="_ _12"> </span><span class="ff6">(<span class="_ _2"></span></span><span class="ls2e">我们整本书都将遵从这个约定<span class="_ _3"> </span><span class="ff6">)<span class="_ _2"></span></span><span class="ls0">。</span></span></div><div class="t m0 x3 h5 y49 ff3 fs2 fc0 sc0 ls2d ws0">Abstract Factory<span class="ff6 ls0 ws1f">( 3 . 1 )<span class="_ _a"></span></span><span class="ff4 ls60">:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它</span></div><div class="t m0 x4 h4 y4a ff4 fs2 fc0 sc0 ls13 ws0">们具体的类。</div><div class="t m0 xd h8 y4b ff9 fs2 fc0 sc0 ls0 ws0">第<span class="ffb">1<span class="_ _2"></span></span>章<span class="_ _13"> </span>引<span class="_ _f"> </span>言<span class="_ _f"> </span><span class="ff8 fs5 fc2">5</span></div><div class="t m0 x1 h2 y1 ff1 fs0 fc0 sc0 ls0 ws0">下载</div></div><div class="pi" data-data='{"ctm":[1.841248,0.000000,0.000000,1.841248,0.000000,0.000000]}'></div></div>