Presentation is loading. Please wait.

Presentation is loading. Please wait.

Design Patterns Lecture 4.

Similar presentations


Presentation on theme: "Design Patterns Lecture 4."— Presentation transcript:

1 Design Patterns Lecture 4

2 Types of Design Patterns
Creational Structural Behavioural Abstract Factory Builder Factory Prototype Singleton Adapter Bridge Composite Decorator Façade Flyweight Proxy Chain of Responsibility Command Interpreter Iterator Mediator Memento Observer State Strategy Template Method Visitor

3 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。
观察者模式 意图 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。 适用性 当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。 当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。

4 Observer模式的实现 由原理不难看出Observer模式的实现关键在于 Subject和Observers间的协同工作。为了响应数据 变更,Observers需要实现接口: abstract interface Observer { public void sendNotify(数据变更); } 然后Observers将其注册到Subject,数据变换时由 其调用接口的sendNotify通知Observers刷新。显 然,Subject需要实现以下接口来接受注册。 abstract interface Subject { public void registerInterest(Observer obs); Subject要通知Observer数据变更,需要采用函数回调的方法,因此要求所有Observers都具有相同的回调函数(也即是它们有共性)。让Observers实现相同的接口,接口里面包含回调函数,问题可解。 Observers将其注册到Subject,也要求Subject有一个统一的接收注册的接口。有了该接口,一个Observer就能注册到多个Subject中。 当需要添加新的数据表现形式,只要创建实现Observers接口的类即可,同理如需要改变数据模型,也只是修改Subject接口的类实现而已。整个系统的弹性非常好,任何一部分的变更都不对其它部分造成任何影响,添加新的特性十分方便。

5 Observer模式与MVC MVC(Model-View-Controller)的核心思 想和Observer模式是完全类似的。数据模型 (业务逻辑)和表现逻辑相互隔离, Controller则负责与客户交互,根据请求调用M 和V的功能。 通常情况下Controller并不单独存在,而是 和M或V结合(JFC中便是如此)。但在分布式 系统中,客户端不可能直接与M或V进行交互, 此时Controller将独立出来并发挥重要作用。 访问协议、请求分发、安全认证、日志记录和 异常处理等都由其承担。 JFC是用于设计交互界面的,客户对数据的控制往往要通过界面(也是View)来完成,所以Controller常与View结合在一起。 分布式系统中,客户与M和V,或者M与V之间都是隔离的(且经常会是物理上的隔离),J2EE环境下是最典型的例子。因此需要靠Controller来与客户端打交道,根据客户的请求调用M和V。此时,Controller变成了整个系统的动力所在,缺少它系统无法运转。由于处于跟用户交互的第一线,访问协议的解释、请求分发、安全认证等重担都落到了Controller的肩上。 总体上看,Observer和MVC在本质上并没有太多的区别,只是应用范围的不同引起差异。MVC通常会用在分布式系统中,而交互式的应用程序一般使用Observer。

6 提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。
迭代子模式 意图 提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。 适用性 访问一个聚合对象的内容而无需暴露它的内部表示。 支持对聚合对象的多种遍历。 为遍历不同的聚合结构提供一个统一的接口(即, 支持多态迭代)。

7 Iterator模式的接口定义 Iterator的接口定义大同小异,可以根据具 体的情况定制。通常情况下,接口定义如下: public interface Iterator { public Object First(); public Object Next(); public boolean hasNext(); public Object CurrentItem(); }

8 Iterator和Composite模式
Composite模式常用于组织树型结构数据,故 同样会面临数据遍历的问题。树型数据的遍历主要 有两种不同的算法:深度优先和广度优先。利用 Iterator,可以将具体的遍历算法屏蔽,客户端也 就不再受算法的困扰。 此外,Iterator还可用于每个节点所包含子节 点的遍历。 需要注意的是Iterator使用的是pull模型来遍历数据,也就是主动获取,这个和后面所介绍的Visitor不同,Visitor采用的是push模型。

9 责任链模式 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 适用性 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 可处理一个请求的对象集合应被动态指定。

10 Chain of Responsibility的实现
该模式的实现关键在于响应链的实现,即是 将所有request的处理类串起来形成响应链。响 应链的操作主要是添加处理类和激发处理类,用 接口表示如下: public interface Chain { public void addChain(Chain c); public void invoke(String mesg); … } 所有的处理类都实现以上接口,即可组成响应链。 要将处理类串起来(形成一个集合,即响应链),前提就是处理类要有共性(实现共同的接口或者虚类),否则无法串到一起。 处理类既然要有共性来形成响应链,自然最关键的共性就是体现响应链的操作。 结合UML类图来说明响应链的结构。 响应链有两种结构:链式和树型。其核心思想是完全一样的,仅仅是数据组织方式的区别而已。

11 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
备忘录模式 意图 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。 适用性 必须保存一个对象在某一个时刻的(部分)状态, 这样以后需要时它才能恢复到先前的状态。 如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。

12 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。
命令模式 意图 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。 适用性 你可用过程语言中的回调(c a l l b a c k )函数表达这种参数化机制。所谓回调函数是指函数先在某处注册,而它将在稍后某个需要的时候被调用。C o m m a n d 模式是回调机制的一个面向对象的替代品。 在不同的时刻指定、排列和执行请求。一个C o m m a n d 对象可以有一个与初始请求无关的生存期。如果一个请求的接收者可用一种与地址空间无关的方式表达,那么就可将负责该请求的命令对象传送给另一个不同的进程并在那儿实现该请求。 支持取消操作。C o m m a n d 的E x c u t e 操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。C o m m a n d 接口必须添加一个U n e x e c u t e 操作,该操作取消上一次E x e c u t e 调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用U n e x e c u t e 和E x e c u t e 来实现重数不限的“取消”和“重做”。 理解的关键是将命令本身和命令的执行体分开,可以以开电脑为例,主板上有开电脑键,激发一个开电脑命令,但是这个命令不是按钮完成的,按钮只是Invoker,真正开机过程的是由主板完成的。

13 Command模式Vs责任链模式 Command模式和响应链都起到了隔离处理 代码和使响应端对客户端透明的作用。
Command模式简化和优化了request到处 理代码的传递,为request的扩展提供良好支持。 责任链只是将传递流程以链式或树型结构管 理起来,为处理代码的激发顺序提供了很好的灵 活性。 在已往的做法中,request到处理代码的传递需要使用大量的if或switch语句及各种判断条件。Command模式将request传递和处理代码进行了彻底的隔离,处理类中不包含任何条件判断。 request传递代码隔离出来后,往往可以借助数组、链表或散列进行简化和优化。因此随着request种类的增长,Command模式能依然保持良好的性能。 响应链实际上只是将if或switch语句转化成链式或者树型的结构管理起来,对于判断条件不作任何处理,仍然保留在处理代码中。故其对request传递没有任何的简化或优化处理,随着request种类的增长,性能瓶颈会逐渐显露,但它提供了处理代码激发顺序的灵活性,这是Command模式无法提供。 当然,这些区别都是由其应用范围所决定的。还要注意的是Command模式并不像响应链,专门为响应request而存在, Command模式还有其它的应用,在后面的举例中将可以看到。

14 Command模式的应用举例 Servlet是完全遵照Command模式设计的。每 个Servlet都包含两个激发函数doGet和doPost。 激活Servlet的URL或Map则在部署文件里设定。 JUnit也是以Command模式为基础的。 TestCase需要通过TestSuit以树型的结构组织起来。 这样就必须将所有TestCase设计成具有统一激活接 口的类。 采用Command模式后,request的传递和处理代码完全分离,因此可以将request的传递规则写到部署文件里面,由容器来解释执行。 由应用举例可以看出Command模式的应用范围: 1.根据不同的request执行相应理代码。 2.将处理代码以一种数据结构组织起来。

15 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
状态模式 意图 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。 适用性 一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常, 有多个操作包含这一相同的条件结构。S t a t e模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

16 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
访问者模式 意图 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 适用性 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Vi s i t o r 使得你可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用共享时,用Vi s i t o r 模式让每个应用仅包含需要用到的操作。 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。

17 Visitor模式的实现 Visitor的实现主要是两个步骤:
所有被访问的对象都要实现函数 public void accept(Visitor v) { v.visit(this); //call visitor method } 遍历数据之前先创建Visitor,然后遍历的过程中调用每个类的accept函数 第一步中,如果访问的对象是不同的,那就要使其实现一个接口或继承于一个基类。 结合一个简单例子讲解 Visitor利用了OOP的多态特性来处理对多个编程接口不同的对象进行访问的问题,简单而富弹性。与传统的方法相比,消除了数量庞大的if和instanceof语句,结构更加清晰。 其次也可以看到,遍历数据逻辑,和数据处理逻辑被完全隔离,在数据遍历相同的情况下,我们只要创建多个Visitor,而不必在每次数据的遍历处理过程中重复数据遍历代码,这对消除代码冗余有很大帮助,尤其是遍历代码涉及复杂的算法或初始化和释放资源操作的时候,效果相当明显。

18 Visitor模式应用举例 典型应用在编译器语法语义分析。

19 Visitor Vs Iterator Visitor和Iterator都是用于数据遍历的,其差 异主要是由所采取的数据读取模式不同而引起。 Visitor使用的推(Push)模型,而Iterator用的则是 拉(Pull)模型。 拉模型更加简单直观,但是推模型能充分利用 OOP的多态来简化代码,优化体系结构。 Iterator可以将数据遍历逻辑封装起来,从而和处理逻辑隔离,但是无法解决访问对象不同情况下的问题,仍然需要采用传统的if和instanceof语句。此外,Iterator采用的是拉模型,故无法实现反控。

20 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器模式 意图 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 适用性 当有一个语言需要解释执行, 并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好: 该文法简单对于复杂的文法, 文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是更好的选择。它们无需构建抽象语法树即可解释表达式, 这样可以节省空间而且还可能节省时间。 效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的, 而是首先将它们转换成另一种形式。例如,正则表达式通常被转换成状态机。但即使在这种情况下, 转换器仍可用解释器模式实现, 该模式仍是有用的。

21 何时引入定制语言 程序必须解释执行任意的字符指令 程序以字 符指令为输入,根据指令执行不同的动作。例 如数学运算和数理统计方面的软件、数据库的 DDL等。 程序必须产生多种多样的输出结果 尽管这些 输出结果和执行流程各异,但它们执行所包含 的操作步骤却是相同的。故需要一种语言来描 述相关的操作。如报表软件、数据库的DML、 转换XML文档的XSL等。 Ddl: data definition language; DML: data manipulation language.

22 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
中介者模式 意图 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。 适用性 一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。 想定制一个分布在多个类中的行为,而又不想生成太多的子类。

23 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
策略模式 意图 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。 适用性 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。 需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时,可以使用策略模式。 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。 一个类定义了多种行为, 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的S t r a t e g y 类中以代替这些条件语句。 完成某个功能有多个选择方案,比如从A到B,可以选择坐火车,也可以选择坐飞机,选择是基于上下文环境的。

24 Template Pattern 意图 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Templ ate Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 适用性 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。这是Opdyke 和Johnsn 所描述过的“重分解以一般化”的一个很好的例子。首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。 控制子类扩展。模板方法只在特定点调用“h o o k ”操作(参见效果一节),这样就只允许在这些点进行扩展。 下面关于行为模式,行为模式涉及到算法和对象间职责的分配。不仅描述对象或者类的模式,还描述了他们之间的通信模式。 模板模式,具体由子类实现的步骤叫做钩子操作,体现了父类对子类扩展的控制


Download ppt "Design Patterns Lecture 4."

Similar presentations


Ads by Google