行为型设计模式总结

行为型设计模式涉及的算法和对象间职责的分配。它不仅描述了对象或类的模式,还描述了它们之间的通信模式。这一点将在本总结中重点分析。那么首先看下各个行为型设计模式的含义。

一、行为型设计模式的含义。

1、观察者模式(Observer Pattern)定义了一种一对多的依赖关系,让多个对象同时关注同一主题。当这个主题对像的状态发生改变时,会通知这些观察者对象,使他们能够自动更新自己

2、命令模式(Command Pattern)将一个请求封装为一个对象,使我们可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销操作。

3、模板模式(Templete Pattern)定义一个操作中的算法骨架,而将一些步骤延迟到了子类。模板方法可以允许子类在不改变一个算法结构的前提下改变一些具体的步骤。

4、职责链模式(Chain of Responsiblity Pattern)是多个对象都有机会处理请求,避免了发送者和接受者之间的耦合。将这些对象连成一条连,并将这个请求沿着这条连传递,直到有对象处理它为止。

5、状态模式(State Pattern)当一个对象状态发生改变时允许改变其行为,这个对象看起来像是改变了其类。

6、备忘录模式(Memento pattern)在不破坏封装性的同时,可以捕获该对象的内部状态,并且在该对象之外可以保存此状态。这样以后就可将该对象恢复到原先的保存状态。

7、策略模式(Strategy pattern)定义了算法家族,将这些算法分别封装起来,使他们之间可以相互替代。此模式让算法的替换不会影响到使用的客户。

8、迭代器模式(iterator pattern)提供一种方法用来顺序的访问聚合对象中各个元素,而又不暴露对象的内部表示。

9、访问者模式(visitor pattern)定义一个作用于某对象内部结构中各个元素的操作。它使我在不改变各个元素的类的前提下定义作用于这些元素的新操作。

10、中介者模式(mediator pattern)定义一个中介者对象用来封装不同对象间的交互。中介者模式使对象不需要显示的相互引用,从而使其耦合松散,而且可以独立的改变它们之间的交互。

11、解释器模式(interpreter pattern)给定一种语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

二、实现上的重点

 1Observer pattern 有两点要注意,一是具体观察观察者(ConcreteObserver)要有具体的主题,其行为会虽具体主题变化而变化;二是主题变化时,要让主题通知所有关心这一主题的观察者更新行为。完成第一个任务则需要在ConcreteObserver中有设置自己关心主题的功能,而如果仅为完成第二个任务则大可在具体的主题(ConcreteSubject)中写入Notify方法,来遍历所有关心此主题的观察者,不过因为每个具体主题都有添加观察者,遍历每个观察者的方法,这样我们应该将其抽象到抽象主题类(Subject)中。

在抽象主题类(Subject)的通知各个观察者更新方法(Notify)中,在遍历每个观察者时会调用观察者的update方法,这时我们注意到,这些观察者行为的名称必须相同,如果不同我们就没办法通知了,而往往它们的方法名是不同的,那我们应该这么办呢?

委托技术对实现上述问题很有帮助。事件委托,允许我们将不同对象的不同方法,同时委托给同一对象的同一事件。这样我们便可以将不同观察者的的不同方法委托给我们的主题类的同一事件了。

这样我们只需在具体主题类中定义可以接受委托的事件,在客户端里将观察者的方法委托给主题类的事件,就可以完成通知的功能了。此时我们还会发现,抽象主题类(subject)也不必知道观察者了,将他们解耦了(不过客户端,稍复杂了点)。实现如下:

具体主题类:

    '定义一个委托事件的结构

    Delegate Sub a() 'EventHandler()

    Public Event Update As a 'EventHandler

 

    '通知观察者时调用委托事件

    Public Sub Notify() Implements ISubject.Notify

        RaiseEvent Update()

    End Sub

客户端

 '将两个观察者关心的事情委托给主题对象update事件

        AddHandler csIns.Update, AddressOf Observer1.CloseTV

        AddHandler csIns.Update, AddressOf Observer2.DoExercise

 

    '主题状体发生改变

        csIns.SubjectState = "老板来了"

        '通知观察者变化

        csIns.Notify()

2、Command Pattern 的意图就是将需要某方法的类与实现某方法的类解耦。这是通过抽象出命令类来做到的,我们可以在需要者类中添加需要的命令来完成它所要的操作。

3、Templete Pattern 通过模板模式的含义很容清楚我们改变的只是算法的细节,至于算法的结构是不能改变的。重点就是在抽象类(Abstract Class)中定义算法结构和该算法的实现细节。

4、Chain of Responsibility Pattern(职责链模式)就是说一个请求在A类中完成不成,自动由A类交由B类去完成,不行再由B类交由C类完成。解除了请求与每个类耦合。主要实现就是在每个类中要定义添加自己的接替类,即我们能完成后要交由谁去完成的类。

5、State Pattern 是说一个类在不同状态下有不同的行为。重点实现是先在不同状态类中实现不同状态下的行为,在行为类中定义设定其状态的方法,这样可以将不同的状态类传入该类中。

6、Memento Pattern(备忘录模式)主要是在需要备忘的类(originator)中产生一个Menento类,这个类储存了要备忘的东西,然后将该类存储在一个收集备忘类的类(Caretaker)中。之后Originator可以在Caretaker中得到自己的备忘属性

7、Strategy Pattern 重点实现就是在需要算法的类(Context)中,如何依据客户的选择,选择算法运算出结果

8、Iterator pattern (迭代器模式说白了就是对一个聚合进行遍历。只不过我们现在不是直接调用这个聚合的方法来遍历了,而是同过迭代器(iterator)来遍历,这样就可以将聚合对象的内部表示隐蔽了。

迭代器其实就是提供了一种对聚合中每个元素进行访问的方法。主要完具体迭代器(concreteIterator)中了first next isDown等方法,再有就是在具体的聚合(ConcreteAggregate)中利用list的类的一些方法完成对其中数据的访问。

迭代器模式中,由于具体的聚合类(ConreteAggregagte)可以产生具体的迭代器(ConcreteIterator),故而我们对客户端可以隐藏具体的迭代器(concreteIterator),只需定义一个抽象的迭代器来接受具体的聚合(concreteAggregate)产生的具体迭代器。

9、Visitor Pattern 的目的是将处理与数据结构分开。如果一个系统的数据结构相对稳定,而且又需要易于变化的算法,使用访问者模式就比较合适了。但我们会发现如果数据结构发生变化则是不好改变的。GOF提到此设计模式不常使用,因为系统的数据结构通常是要发生变化的。其重点实现:

(1)在对象结构类(ObjectStructure)中,可以添加和删除元素类,并且能过运行这些元素类的操作。不过每个元素类的操作在不同的Visitor类的条件下有不同的实现

(2)Visitor类不与Element类显示接触,而是通过访问ObjectStructure类来接触,即在objectStructure类中将Visitor类传递给Element类。

(3)每个element类中 的方法是调用visitor类中的方法实现的

(4)Visitor类中的方法在不同的Element下表现不同(即在element类中调用Visitor类的方法时也要传入自身element

10、Mediator pattern要完成的是使不同的对象间的交互不必显示的交互,即Meidator类封装了不同对象间的交互。这一点主要是在对象调用方法传递信息时直接调用mediator类的方法,然后在Mediator类的方法中完成两队象的交互。

11、Interpretor pattern的使用是当有一个语言需要解释执行,并且我可以将这个语言中的句子表示成抽象的语法树时,便可使用解释器模式。

三、比较

1、策略模式(strategy pattern)、命令模式(Command Pattern)、职责链模式(Chain of Responsibity Pattern)、状态模式(State Pattern)。

四个模式的比较图

看这几个类图,我们发现状态模式和策略模式极为相似。不过状态模式要解决的是一个对象处在不同的状态时会有不同的行为,但状态的判断非常复杂,甚至是每一个状态中又会包含很多的判断(如状态有上午,中午,下午,但这三个状态中每一个状态下又会包括很多判断处于哪个时段的判断)的问题,这时我们用状态模式将复杂的判断转移给了其他几个类判断;而策略模式就是与行为有关,一种策略就仅是一种计算方法。

职责链模式中每个子类也是对应着一定范围的行为,它与策略模式的不同就在于第一个类做不了的事情直接交与下一个类做,而这个过程不必在客户端写代码完成,这几个类是一级一级的关系;策略模式则不会是这样,具体的算法是平级的,只是看客户选择那种算法。

命令模式与上述三个模式在表现形式上有较明显的区别。前三个模式中,需要某行为的类都知道实施此行为的类,而命令模式则将需要某行为的类与实施此行为的类分开了。从意图上,前三个模式都是让需要某行为的类可以选择不同的实施此行为的类;而命令模式则是为了让实施某行为的类可以给不同的需要此行为的类。

2、访问者模式同状态模式的比较

两者看上去都是某个类在不同条件下会有不同的行为表现。每个类的行为并非在自己本身上,而是寄托给了条件类了。不过这个条件在状态模式中用State类表示,在访问者模式中用visitor类表示。

两者的不同点是:

(1)状态模式中这些状态下的行为全部属于一个类,而访问者模式中每个条件下都会有不同类的行为;而且状态模式中的每个具体的状态类中还可能包还对细小状态的判断。

(2)条件与需要此条件的类的接触方式不同,状态模式是将条件直接赋予需要的类,而访问者模式则是通过objectStructure来“访问”;

(3)最重要的应该是两者的目的不同:状态模式是要更好的执行一个类不同状态下的行为,而访问者模式则可以从ObjectStructure类中看出,它是一个结构固定的类,但这个结构下的算法是变化的。

3、访问者模式同模板方法的比较

访问者模式和模板方法都是结构固定,细节可以改变。不过访问者模式固定的是对象结构类(objectStructure)中的元素类,可以改变的是这个对象结构类中的元素类的方法,也就是说组成系统结构的类是不易变化的,但这些类的方法是很容易变化的;同访问者模式不同,模板模式仅是用于一个类的算法细节的改变上。

4、observer pattern 和 结构型设计模式中的外观模式在功能

我感觉observer pattern 和 结构型设计模式中的外观模式在功能上有些相似。它们都是由一个类(A)的动作引起另外多个类变化。但为什么一个是行为型设计模式一个却是结构型设计模式呢?一方面是因为那个引发类(A)的身份不同,另一方面则是因为引起多个类变化的原因不同。前者是行为的需要,后则却是结构上的需要。

观察者模式中的类A就是主题类(Subject,外观模式中的类A就是外观类(Facade)。观察者模式中Subject类的是独立的,不是为了什么,为了谁才有的;而外观模式中的facade类却不是独立的,它的出现是带有强烈目的的——为了规划子系统。再有,Observer Pattern引起其他类变化,是因为这些类需要,可以说使这些类给了Subject类通知它们的权利;而Facade pattern中引起其他类变化却是系统的需要,是Facade类强烈要求它们改变的,是系统付给的权利。可以说Facade类并未担任系统的具体工作,而Subject类却担任了。

拿我们的机房收费系统做例子。学生可能会在某一时刻退卡(消除账户),一旦退卡系统就必须要完成一下工作。

1)消除充值记录信息

2)消除上机记录信息

3)计算所剩余额并返还给学生

在这我们依据上面对外观模式和观察者模式的分析,会很清楚的发现这属于观察者模式,而非外观模式。因为这是其他(像消除充值记录、计算余额等)模块(类)的行为需要,而非系统的结构需求;另外退卡本身就是系统的一个任务,是其他模块(类)关注的主题。

四、小做剖析

1、Command Pattern中大话设计模式举的例子的思考

    在大话设计模式中有对Command Pattern的优点有这样一句评价:命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分开。我认为其中的第二个“一个”应该改为“这个”。如果是这样的话,前一个对象就应该对应着设计模式中的Invoker,而后一个对象则对应着设计模式中的Receiver。那么大话设计模式中举得烤羊肉的例子就不合适了。

比较

 Invoker我感觉应该翻译成:调用者。我们要搞清楚到底谁是调用者命令的类,也就是说是谁要完成某项工作。在买烤羊肉时,这正需要实现烧一串羊肉的人是顾客,而不是服务员,依照命令模式的要领我们要做的是将这正需要完成烧一串羊肉的人与能够实现烧一串羊肉的人分开,也就是说要把顾客和厨师分开。而在此例中服务员和厨师是怎么也分不开的(服务员得通知厨师要做什么)。怎么改善就成了呢,我认为那些命令类就是这个店里服务员持有的菜单

烤羊肉

 正如Command Pattern的含义,将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

1、职责链模式补充状态模式

职责链模式和状态模式

    使用状态模式时会使用到职责链模式来配合使用。在Stata PatternContext类会根据不同的状态做不同的事情,然而我们不是时时都能清楚context接受的数据处于Context类的何种状态,此时我们就应该使用职责链模式将这些具体状态的职责代替者写明,context类获得的状态如果不属于状态1,则由状态2代理来管理依次类推……

2、备忘录模式

     在对一个类的状态(属性)进行保存以便恢复时,为什么不不像prototype pattern实现ICloneable接口的Clone方法。原因之一使用便是利用这个clone 方法会将这个类的所有东西全备份,而这有时不是我们全部需要的的;

    Memento patternCommand pattern中可撤销操作的完善。在命令模式中支持撤销操作,这一点就应该交给备忘录模式来完成。

这个模式可以对客户端隐藏备份的属性(备忘录类——memento(是不是每个模式都会通过一定手段是客户端与某些类解偶和呢)

五、总结

这些行为型设计模式涉及的是算法和对象间职责的分配。可以说它们解决的是不同方面的大问题,但在多数情况下这些设计模式是相互配合使用的。这些模式中有的是在封装变化上突出、有的是将对象作为参数上突出、有的是对象间通信方式上突出、还有的是对信息发送者和接受者解耦。大致归类如下:

1、封装变化角度

(1)Strategy Pattern

(2)State Pattern

(3)Mediator Pattern

(4)Iterator Pattern

2、对象作为参数

(1)Visitor Pattern

(2)Memento Pattern

(3)Command Pattern

(4)Interpreter Pattern

3、对象间通信方式上

(1)Observer Pattern

(2)Mediator Pattern

4、对发送者和接受者解耦

Chain of Responsibility Pattern、命令、观察者、中介者等模式都有所涉及

备注:在此处用英文写的设计模式是第一次出现的位置。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值