设计模式之行为模式(第一版)
职责链模式
职责链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
Handler类,定义一个处理请示的接口。
ConcreteHandler类,具体处理者类,处理它所负责的请求,可访问它的后继者,如果可处理该请求,就处理之,否则就将该请求转发给它的后继者。ConcreteHandler1,当请求数为0~10则有权处理,否则转到下一位。
ConcreteHandler2,当请求数为10~20则有权处理,否则转到下一位。
ConcreteHandler3,当请求数为20~30则有权处理,否则转到下一位。
客户端代码,向链上的具体处理者对象提交请求。
第二例子–加薪代码重构
Request请求类与原来一样。
经理类就可以去继承这个’管理者’类,只需重写’申请请求’的方法就可以了
总监’类同样继承’管理者类’
总经理’的权限就是全部都需要处理。
由于我们把你原来的一个’管理者’类改成了一个抽象类和三个具体类,此时类之间的灵活性就大大增加了,如果我们需要扩展新的管理者类别,只需要增加子类就可以。比如这个例子增加一个’集团总裁’类,完全是没有问题的,只需要修改’总经理类’即可,并不影响其他类代码。目前,还有一个关键,那就是客户端如何编写
结果显示:
命令模式
命令模式(Command),将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
Command类,用来声明执行操作的接口。
ConcreteCommand类,将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现executeCommand。
Invoker类,要求该命令执行这个请求。
Receiver类,知道如何实施与执行一个与请求相关的操作,任何类都可能作为一个接收者。
客户端代码,创建一个具体命令对象并设定它的接收者。
第二例子–烤羊肉串
烤肉串者类与之前相同。
抽象命令类:
具体命令类:
服务员类:
客户端代码:
基本都把代码实现了。但没有体现出命令模式的作用。比如下面几个问题:第一,真实的情况其实并不是用户点一个菜,服务员就通知厨房去做一个,那样不科学,应该是点完烧烤后,服务员一次通知制作;第二,如果此时鸡翅没了,不应该是客户来判断是否还有,客户哪知道有没有呀,应该是服务员或烤肉串者来否决这个请求;第三,客户到底点了哪些烧烤或饮料,这是需要记录日志的,以备收费,也包括后期的统计;第四,客户完全有可能因为点的肉串太多而考虑取消一些还没有制作的肉串。这些问题都需要得到解决。
进一步改进命令模式
客户端代码:
结果显示:
命令模式的作用:
第一,它能较容易地设计一个命令队列;
第二,在需要的情况下,可以较容易地将命令记入日志;
第三,允许接收请求的一方决定是否要否决请求
第四,可以容易地实现对请求的撤销和重做;
第五,由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易
命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开
迭代器模式
迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
Aggregate聚集抽象类:
ConcreteAggregate具体聚集类:继承Aggregate。
Iterator迭代器抽象类:
ConcreteIterator具体迭代器类:继承Iterator。
客户端代码:
结果显示:
Java的迭代器实现
Java.util.Iterator支持对集合的简单迭代接口。
Java.util.ListIterator支持对集合的任意方向上迭代接口。
foreach而在编译器里做了些什么呢?其实它做的是下面的工作。
如果我们想实现刚才的反向遍历。那就用另一个接口实现。
迭代器(Iterator)模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可以让外部代码透明地访问集合内部的数据。
中介者模式
中介者模式(Mediator),用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
Colleague叫作抽象同事类,而ConcreteColleague是具体同事类,每个具体同事只知道自己的行为,而不了解其他同事类的情况,但他们却都认识中介者对象,Mediator是抽象中介者,定义了同事对象到中介者对象的接口,ConcreteMediator是具体中介者对象,实现抽象类的方法,它需要知道所有具体同事类,并从具体同事接收消息,向具体同事对象发出命令。
Colleague类:抽象同事类。
ConcreteColleague1和ConcreteColleague2等各种同事对象:
Mediator类:抽象中介者类。
ConcreteMediator类:具体中介者类。
客户端代码:
第二例子–安理会作中介
国家类:相当于Colleague类。
美国类:相当于ConcreteColleague1类。
伊拉克类:相当于ConcreteColleague2类。
联合国机构类:相当于Mediator类。
联合国安理会:相当于ConcreteMediator类。
客户端调用:
结果显示:
中介者模式的优点首先是Mediator的出现减少了各个Colleague的耦合,使得可以独立地改变和复用各个Colleague类和Mediator,比如任何国家的改变不会影响到其他国家,而只是与安理会发生变化。其次,由于把对象如何协作进行了抽象,将中介作为一个独立的概念并将其封装在一个对象中,这样关注的对象就从对象各自本身的行为转移到它们之间的交互上来,也就是站在一个更宏观的角度去看待系统。
由于ConcreteMediator控制了集中化,于是就把交互复杂性变为中介者的复杂性,这就使得中介者会变得比任何一个ConcreteColleague都复杂。事实上,联合国安理会秘书长的工作应该是非常繁忙的,谁叫他就是’全球最大的官’呢。也正因为此,中介者模式的优点来自集中控制,其缺点也是它,使用时要考虑清楚哦。
备忘录模式
备忘录(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可使用备忘录恢复内部状态,Originator可根据需要决定Memento存储Originator的哪些内部状态。
Memento(备忘录):负责存储Originator对象的内部状态,并可防止Originator以外的其他对象访问备忘录Memento。备忘录有两个接口,Caretaker只能看到备忘录的窄接口,它只能将备忘录传递给其他对象。Originator能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。
Caretaker(管理者):负责保存好备忘录Memento,不能对备忘录的内容进行操作或检查。
发起人(Originator)类:
备忘录(Memento)类:
管理者(Caretaker)类:
客户端程序:
第二例子–游戏进度备忘
游戏角色类:
角色状态存储箱类:
角色状态管理者类:
客户端代码:
参考:大话设计模式–程杰