版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第七章 行为型设计模式返回目录l目录l【7.1】 模板方法模式模板方法模式(Template method) l 7.2 观察者模式(Oberserver) 【实验】l【7.3】 迭代子模式(Iterator) l 7.4 责任链模式(Chain of Responsibility)【实验】 l 7.5 备忘录模式(Memento) 【实验】l 7.6 命令模式 (Command) 【实验】l 7.7 状态模式(State) l【7.8】 访问者模式(访问者模式(Visitor)l【7.9】 中介者模式(中介者模式(Mediator) l【7.10】 策略模式(策略模式(Strategy) 返
2、回目录7.1 模板方法(Template Method)模式一、模板方法模式的由来二、模板方法模式的意图及适用性三、模板方法模式的结构及参与者四、应用举例五、效果分析返回目录7.1.1 模板方法模式的由来l行为型设计模式关注的焦点之一就是类对象的职责分配,而模板方法实现父类和子类对象之间职责的划分。返回目录7.1.1 模板方法模式的由来ABC类类CaC.A()返回目录7.1.1 模板方法模式的由来ABC类类CaC.A()ABCABC返回目录7.1.1 模板方法模式的由来ABC类类CaC.D()ABCABCD返回目录7.1.1 模板方法模式的由来ABC父类父类aC.D()ABCABCABCABC
3、ABCABCABCABC子类子类返回目录7.1.1 模板方法模式的由来l比如就本科生如何培养这项工作,教育部制定纲领性政策,l如:军训-学文化课-做毕业设计-毕业l至此,教育部的工作完成了。l接下来学生具体怎么军训,怎么上课,怎么做毕业设计等,就是各学校的职责了。返回目录7.1.1 模板方法模式的由来l教育部和学校之间通过上下级分工的方式分别完成了制定流程和具体实现2项工作。l这种思维模式引入到软件设计中,就是Template methodlTemplate method使用继承机制使得父类和子类之间达到分工合作的目的,父类完成流程(算法、框架),子类实现其具体工作。返回目录7.1.2 模板方
4、法模式的意图和适用性l定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中。返回目录7.1.2 模板方法模式的意图和适用性lTemplate Method模式一般应用在具有以下条件的应用中:l- 具有统一的操作步骤或操作过程- 具有不同的操作细节 即存在多个具有同样操作步骤的应用场景,但某些具体的操作细节却各不相同 返回目录模板方法模式中的两种方法l代表这些具体逻辑步骤的方法称做基本方法(primitive method);l将这些基本法方法总汇起来的方法叫做模版方法(template method),这返回目录摸板方法(Template Method)模式小结l 摸板方法(Templat
5、e Method)模式是一种非常简单而又经常使用的设计模式.先创建一个父类,把其中的一个或多个方法留给子类去实现,这实际上就是在使用摸板模式.l 所谓的摸板模式可以这样来理解:在一个类中定义一个算法,但将此算法的某些细节留到子类中去实现.换句话说,基类是一个抽象类,那么你就是在使用一种简单形式的摸板模式.l 更近一步可以这样来理解:准备一个抽象类,将部分逻辑以具体方法的形式实现,然后申明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方法实现这些抽象方法,从而对剩余的逻辑有不同的实现.返回目录7.1.3 模板方法模式的结构和参与者返回目录7.1.3 模板方法模式的结构和参与者1)A
6、bstractClass, 定义抽象的原语操作,具体子类将重定义他们以实现一个算法的各步骤 实现一个模板方法,定义一个算法的骨架。该模板不仅调用原语操作,也调用定义在AbstractClass或其他对象中的操作2)ConcreteClass 实现原语操作以完成算法中与特定子类相关的步骤返回目录教材上的应用举例l取款单模板l7.1.2返回目录7.1.4 应用举例l就前面所举的本科生培养的例子,给出其代码实现的示例。l看看如何实现父类与子类的分工,即教育部本科生培养处与各高校的本科生培养处如何实现职责划分返回目录7.1.4 应用举例l public abstract class 教育部本科生培养处
7、 /这就是一个,定义了算法的骨架 public void 本科生培养() l 军训(); 上课(); 毕业设计(); 授予学位(); /这里还可以有其它培养内容l protected abstract void 军训(); protected abstract void 上课(); protected abstract void 毕业设计(); protected abstract void 授予学位(); 返回目录7.1.4 应用举例 public class 清华大学本科生培养处 : 教育部本科生培养处 protected override void 军训() /站军姿l /正步走 pro
8、tected override void 上课() /具体课程l protected override 毕业设计() /开题,论文,答辩l protected override 授予() /授予仪式 返回目录7.1.4 应用举例l public class App l l static void Main() l l 教育部本科生培养处 PYC=new 清华大学本科生培养处();l PYC.本科生培养();l Console.Read(); /等待用户输入 l 返回目录实用例子lHttpServlet技术l造电脑的示例l数据库访问的模板方法l有趣的模板方法模式:造悍马汽车返回目录7.1.5 效
9、果分析l模板方法是一种代码复用技术,提取了“子类”的公共行为l模板方法导致一种反向的控制结构:“你别来找我,让我去找你”,即:一个父类调用子类的操作,而不是相反。返回目录关于继承的讨论l模版方法模式鼓励恰当地使用继承。此模式可以用来改写一些拥有相同功能的相关的类,将可复用的l一般性的行为代码移到基类里面,而把特殊化的行为代码移到子类里面。l因此,熟悉模版方法模式便成为一个重新学习继承的好地方。返回目录7.2 观察者模式(Oberserver) 【实验】 一.观察者模式的由来二.观察者模式的意图及适用性三.观察者模式的结构及参与者四.应用举例五.效果说明返回目录7.2.1 观察者模式的由来l在制
10、作系统的过程中,将一个系统分割成一系列相互协作的类有一个常见的副作用:需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,因为这样降低了他们的可充用性。返回目录7.2.1 观察者模式的由来 例如, 许多图形用户界面工具箱将用户应用的界面表示与底下的应用数据分离。定义应用数据的类和负责界面表示的类可以各自独立地复用。当然它们也可一起工作。一个表格对象和一个柱状图对象可使用不同的表示形式描述同一个应用数据对象的信息。表格对象和柱状图对象互相并不知道对方的存在,这样使你可以根据需要单独复用表格或柱状图。但在这里是它们表现的似乎互相知道。当用户改变表格中的信息时,柱状图能立即反映这一
11、变化, 反过来也是如此。返回目录7.2.1 观察者模式的由来 这一行为意味着表格对象和棒状图对象都依赖于数据对象, 因此数据对象的任何状态改变都应立即通知它们。同时也没有理由将依赖于该数据对象的对象的数目限定为两个, 对相同的数据可以有任意数目的不同用户界面。7.2.2 观察者模式的意图和适用性l模式的意图 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 返回目录7.2.2 观察者模式的意图和适用性l 在下面的三种情况下均可使用Observer模式:l 当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以
12、使它们可以各自独立地改变和复用。l 当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。l 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。返回目录7.2.3 观察者模式的结构和参与者l观察者模式结构图返回目录7.2.3 观察者模式的结构和参与者 Observerl Subject(目标) 目标知道它的观察者。可以有任意多个观察者观察同一个目标。 提供注册和删除观察者对象的接口。l Observer(观察者) 为那些在目标发生改变时需获得通知的对象定义一个更新接口。l Concrete Subject(具体目标) 将有关状态
13、存入各Concrete Observer对象。 当它的状态发生改变时, 向它的各个观察者发出通知。l Concrete Observer(具体观察者) 维护一个指向Concrete Subject对象的引用。 存储有关状态,这些状态应与目标的状态保持一致。 实现Observer的更新接口以使自身状态与目标的状态保持一致。返回目录7.2.4 应用举例 例如:班主任老师有电话号码,学生需要知道班主任老师的电话号码以便于在合适时的时候拨打,在这样的组合中,老师就是一个被观察者(Subject),学生就是需要知道信息的观察者,当老师的电话号码发生改变时,学生得到通知,并更新相应的电话记录。该应用的类图
14、如下图所示。返回目录应用举例返回目录7.2.4 应用举例相关代码:Subject代码:package observer; public interface Subject /目标类的定义public void attach(Observer o); /注册一个观察者public void detach(Observer o); /删除一个观察者public void notice(); /通知所有观察者更新Observer代码:package observer;public interface Observer /观察者类定义public void update(); /更新观察者返回目录7.
15、2.4 应用举例Teacher代码;package observer;import java.util.Vector;public class Teacher implements Subjectprivate String phone; /电话号码private Vector students; /学生public Teacher()phone = ;students = new Vector();public void attach(Observer o)students.add(o);/注册学生public void detach(Observer o)students.remove(o
16、);删除学生public void notice() /通知学生更新 for(int i=0;istudents.size();i+) (Observer)students.get(i).update();public void setPhone(String phone)this.phone = phone;notice();public String getPhone()return phone;返回目录7.2.4 应用举例Student代码:package observer;public class Student implements Observerprivate String na
17、me; /学生姓名private String phone; /班主任老师电话private Teacher teacher;public Student(String name,Teacher t) = name;teacher = t;public void show()System.out.println(Name:+name+nTeachers phone:+phone);public void update() /更新电话号码与老师的保持一致phone = teacher.getPhone(); 返回目录7.2.4 应用举例 Client代码:package obs
18、erver;import java.util.Vector;public class Clientpublic static void main(String args)Vector students = new Vector(); /定义学生类向量Teacher t = new Teacher(); /定义老师类对象for(int i= 0 ;i10;i+) Student st = new Student(lili+i,t); students.add(st); /把学生加到向量中 t.attach(st); /老师注册一个学生t.setPhone(“123);for(int i=0;i1
19、0;i+) (Student)students.get(i).show(); /所有学生的老师电话都为123t.setPhone(“456);for(int i=0;i10;i+) (Student)students.get(i).show(); /所有学生的老师电话都为456返回目录7.2.5 效果分析观察者模式的应用场景:l对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。l对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。返回目录7.2.5 效果分析观察者模式的优点:lSubject和Observer之间是松偶合的,分别可以各自独立改变。lSubjec
20、t在发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知。l遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。返回目录7.2.5 效果分析观察者模式的缺陷:l松偶合导致代码关系不明显,有时可能难以理解。l如果一个Subject被大量Observer订阅的话,在广播通知的时候可能会有效率问题。返回目录7.3迭代子模式(Iterator)一、迭代子模式的由来二、迭代子模式的意图及适用性三、迭代子模式的结构及参与者四、应用举例五、效果分析返回目录7.3.1 迭代子模式的由来l 以集合对象为例,集合是一个管理和组织数据对象的数据结构。这就
21、表明集合首先应具备一个基本属性,就是集合能够存储数据。这其中包含存储数据的类型、存储空间的大小、存储空间的分配、以及存储的方式和顺序。不具备这些特点,则该对象就不成其为集合对象。也就是说,上述这些属性是集合对象与身俱来的,是其密不可分的职责。l 然而,集合对象除了能够存储数据外,还必须提供访问其内部数据的行为方式,这是一种遍历机制。同时这种遍历方式,或会根据不同的情形提供不同的实现,如顺序遍历,逆序遍历,或是二叉树结构的中序、前序、后序遍历。返回目录7.3.1 迭代子模式的由来顺序逆序中序后序存储 聚合类遍历机制返回目录7.3.1 迭代子模式的由来顺序逆序中序后序存储 迭代类聚合类返回目录7.
22、3.1 迭代子模式的由来l 迭代子模式实际上做的工作就是把对象的职责分离。职责分离,可以最大限度地减少彼此之间的耦合程度,从而建立一个松散耦合的对象网络。l 职责分离的要点是对被分离的职责进行封装,并以抽象的方式建立起彼此之间的关系。例如,我们往往将这些可能变化的对象抽象为接口和抽象类,从而将原来的具体依赖改变为抽象依赖。对象不再受制于具体的实现细节约束返回目录7.3.1 迭代子模式的由来l现在我们已经分辨出集合对象拥有的两个职责:一是存储内部数据;二是遍历内部数据。从依赖性来看,前者为集合对象的根本属性,而后者既是可变化的,又是可分离的。因此,我们将遍历行为分离出来,抽象为一个迭代器,专门提
23、供遍历集合内部数据对象的行为。这就是迭代子模式的本质。返回目录7.3.2 迭代子模式的意图和适用性l模式的意图 迭代子模式的目的是设计一个迭代器,这迭代器提供一种方法,可以顺序访问一个聚合对象中的各个元素,但又不暴露该对象的内部表示返回目录7.3.2 迭代子模式的意图和适用性l以下情况可以使用迭代子模式:l1.访问一个聚合对象的内容而无需暴露它的内部表示。l2.支持对聚合对象的多种遍历。l3.为遍历不同的聚合结构提供一个统一的接口 (即, 支持多态迭代)。返回目录7.3.3 迭代子模式的结构和参与者l迭代子模式结构图返回目录7.3.3 迭代子模式的结构和参与者l 迭代器迭代器(Iterator
24、) 迭代器定义访问和遍历元素的接口。l 具体迭代器具体迭代器(ConcreteIterator)1.具体迭代器实现迭代器接口。2.对该聚合遍历时跟踪当前位置。l 聚合聚合(Aggregate)聚合定义创建相应迭代器对象的接口。l 具体聚合具体聚合(ConcreteAggregate)具体聚合实现创建相应迭代器的接口,该操作返回 具体迭代器 的一个适当的实例。返回目录7.3.4 应用举例两种实现方式l 1 白箱聚集与外禀迭代子:白箱聚集向外界提供访问自己内部元素的接口,从而使得外禀迭代子,可以通过聚集提供的方法实现迭代功能。l 2 黑箱聚集内禀迭代子:黑箱聚集不向外界提供遍历自己的元素的接口,因
25、此聚集的成员只能被聚集内部的方法访问。由于内禀迭代子恰好是聚集的成员,因此可以访问聚集元素。返回目录应用举例之白箱例子Aggregate:abstract public class Aggregate public Iterator createIterator() return null; Iterator:public interface Iterator void first(); void next(); bool isDone(); Object currentItem();Aggregateiterator思考:两者如何连接返回目录应用举例之白箱例子Aggregateiterato
26、rcreateIterator()Aggregate返回目录应用举例之白箱例子public class ConcreteAggregate : Aggregate private Object objs = Monk Tang , Monkey, Pigsy, Sandy”; public Iterator createIterator() return new ConcreteIterator(this); public Object getElement(int index) if(index objs.Length) return objsindex; else return null;
27、 public int size() return objs.Length; createIterator() ConcreteAggregate返回目录public class ConcreteIterator implements Iterator private ConcreteAggregate agg; private int index = 0; private int size = 0; public ConcreteIterator(ConcreteAggregate agg) this.agg = agg; size = agg.size(); index = 0 ; pub
28、lic void first() index = 0 ; public void next() if (index = size); public Object currentItem() return agg.getElement(index); ConcreteIterator 迭代类聚合类Firstnext聚合类引用返回目录Client:public class Client private Iterator it; private Aggregate agg = new ConcreteAggregate();public void operation() it = agg.creat
29、eIterator(); while( !it.isDone() ) System.out.println(it.currentItem().toString(); it.next(); public static void main(String args) Client client = new Client(); client.operation(); 返回目录应用举例之白箱例子createIterator() ConcreteAggregate迭代类聚合类Firstnext返回目录应用举例之黑箱例子Iterator:public interface Iterator void firs
30、t(); void next(); boolean isDone(); Object currentItem();Aggregate:abstract public class Aggregate public Iterator createIterator() return null; 返回目录ConcreteAggregate:public class ConcreteAggregate extends Aggregate private Object objs = Monk Tang,Monkey, Pigs,Sandy, Horse; public Iterator createIte
31、rator() return new ConcreteIterator(); private class ConcreteIterator implements Iterator private int currentIndex = 0; public void first() currentIndex = 0; public void next() if ( currentIndex = 0 & request = 10 & request = 20 & request 30 ) Console.WriteLine(0 handled request 1, this,
32、 request ); else if( successor != null ) successor.HandleRequest( request ); 返回目录 / Client test public class Client public static void Main( string args ) / Setup Chain of Responsibility Handler h1 = new ConcreteHandler1(); Handler h2 = new ConcreteHandler2(); Handler h3 = new ConcreteHandler3(); h1
33、.SetSuccessor(h2); h2.SetSuccessor(h3); / Generate and process request int requests = 2, 5, 14, 22, 18, 3, 27, 20 ; foreach( int request in requests ) h1.HandleRequest( request ); 返回目录l 责任链模式并不创建责任链。责任链的创建必须由系统的其它部分创建出来。l 责任链模式降低了请求的发送端和接收端之间的耦合,使多个对象都有机会处理这个请求。一个链可以是一条线,一个树,也可以是一个环。如下图所示,责任链是一个树结构的
34、一部分。返回目录1) 优点:责任链模式的最大的一个有点就是给系统降低了耦合性,请求的发送者完全不必知道该请求会被哪个应答对象处理,极大地降低了系统的耦合性。 2) 缺点:消息传递和处理不当会出现消息的循环重复执行。7.4.5 效果分析返回目录7.5 备忘录模式(Memento) 【实验】一、备忘录模式的由来二、备忘录模式的意图及适用性三、备忘录模式的结构及参与者四、应用举例五、效果分析返回目录7.5.1 备忘录模式的由来l没有人想犯错误,但是没有人能够不犯错误。犯了错误一般只能改过,却很难改正(恢复)。世界上没有后悔药,但是我们在进行软件系统的设计时候是要给用户后悔的权利(实际上可能也是用户要
35、求的权利),我们对一些关键性的操作肯定需要提供诸如撤销 (Undo)的操作。那这个后悔药就是 Memento 模式提供的。7.5.2 备忘录模式的意图和适用性模式的意图 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态返回目录7.5.2 备忘录模式的意图和适用性在以下情况下使用备忘录模式:l必须保存一个对象在某一个时刻的 (部分)状态, 这样以后需要时它才能恢复到先前的状态。l如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。返回目录7.5.3备忘录模式的结构和参与者备忘录模式结构图:返回目
36、录7.5.3 备忘录模式的结构和参与者:1) 备忘录(Memento):备忘录存储原发器对象的内部状态;防止原发器以外的其他对象访问备忘录。2) 原发器(Originator):原发器创建一个备忘录,用以记录当前时刻它的内部状态;使用备忘录恢复内部状态。返回目录/Originatorclass Originator public: typedef string State; Originator(); Originator(const State& sdt); Originator(); Memento* CreateMemento(); void SetMemento(Memento
37、* men); void RestoreToMemento(Memento* mt); State GetState(); void SetState(const State& sdt); void PrintState(); private: State _sdt; Memento* _mt; ; 7.5.4 应用举例返回目录Originator:Originator() _sdt = ; _mt = 0; Originator:Originator(const State& sdt) _sdt = sdt; _mt = 0; Originator:Originator()
38、Memento* Originator:CreateMemento() return new Memento(_sdt); 返回目录State Originator:GetState() return _sdt; void Originator:SetState(const State& sdt) _sdt = sdt; void Originator:PrintState() cout_sdt._sdt = mt-GetState(); 返回目录/ Mementoclass Memento private: friend class Originator; /这是最关键的地方,将Or
39、iginator为friend类,可以访问内部信息,但是其他类不能访问 typedef string State; Memento(); Memento(const State& sdt); Memento(); void SetState(const State& sdt); State GetState(); private: State _sdt; ; 返回目录/class Memento Memento:Memento() Memento: Memento() Memento:Memento(const State& sdt) _sdt = sdt; State
40、 Memento:GetState() return _sdt; void Memento:SetState(const State& sdt) _sdt = sdt; 返回目录/main.cpp int main(int argc,char* argv) Originator* o = new Originator(); o-SetState(“old”); /备忘前状态 o-PrintState(); Memento* m = o-CreateMemento(); /将状态备忘 o-SetState(“new”); /修改状态 o-PrintState(); o-RestoreTo
41、Memento(m); /恢复修改前状态 o-PrintState(); return 0; 返回目录优点:1)保持封装边界;使用备忘录可以避免暴露一些只应由原发器管理却又必须存储在原发器之外的信息。该模式把可能很复杂的原发器内部信息对其他对象屏蔽起来,从而保持了封装边界。2)简化原发器;在其他的保持封装性的设计中 ,原发器负责保持客户请求过的内部状态版本。这就把所有存储管理的重任交给了原发器。让客户管理它们请求的状态将会简化原发器,并且使得客户工作结束时无需通知原发器。缺点:1)定义窄接口和宽接口;在一些语言中可能难以保证只有原发器可访问备忘录的状态。2)使用备忘录可能代价很高;如果原发器在
42、生成备忘录时必须拷贝并存储大量的信息 ,或者客户非常频繁地创建备忘录和恢复原发器状态,可能会导致非常大的开销。除非封装和恢复原发器状态的开销不大,否则该模式可能并不合适。7.5.5 效果分析返回目录7.6 命令模式 (Command) 【实验】一.命令模式的由来二.模式意图和适用性三.模式结构和参与者四. 实例说明五. 效果分析返回目录7.6.1 命令模式的由来 将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。返回目录一个菜单控件的例子返回目录PasteCommand命令返回目录OpenCommand命令返回目录MacroCo
43、mmand命令脚本返回目录7.6.3 命令模式的意图和适用性意图:l将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作 返回目录7.6.3 命令模式的意图和适用性适用性:抽象出待执行的动作以参数化某对象在不同的时刻指定、排列和执行请求支持取消操作(Unexecute)支持修改日志用构建在原语操作上的高层操作构造一个系统返回目录7.6.4 命令模式的结构和参与者返回目录7.6.4 命令模式的结构和参与者Commandu声明执行操作的接口ConcreteCommandu将一个接收者对象绑定于一个动作u调用接收者相应的操作,以实现Exec
44、uteClient(Application)u创建一个具体命令对象并设定它的接收者Invoker(MenuItem)u要求该命令执行这个请求Receiver(Document,Application) u知道如何实施与执行一个请求相关的操作返回目录7.6.4 应用举例菜单控件的代码实例Command抽象类返回目录OpenCommand命令返回目录PasteCommand命令返回目录7.6.5 命令模式效果分析Command模式将调用操作的对象与知道如何实现该操作的对象解耦Command是头等 的对象,它们可像其他的对象一样被操纵和扩展可将多个命令装配成一个复合命令可以很容易的增加新的Comma
45、nd对象,因为这无需改变已有的类。返回目录7.7 状态模式(State)一.模式的由来二.状态状态模式的意图及适用性三.状态模式的结构及参与者四.应用举例五.效果说明返回目录7.7.1 状态模式的由来 一个对象有多种状态,在不同的状态下,对象可以有不同的行为。返回目录7.7.1 状态模式的由来状态变量sSwitch s Case 1 do o1 s=3 Case 2 do o2 s=2 End switchContext类初始状态1状态变化:13 2思考:缺陷在哪里?O1O2O3操作返回目录7.7.1 状态模式的由来Context类状态1类状态2类状态3类状态类思考:两者如何连接?O1O2O3
46、返回目录7.7.1 状态模式的由来状态对象Context类状态1类状态2类状态3类状态类初始化思考:状态操作放在哪里?O1O2O3返回目录7.7.1 状态模式的由来状态对象Context类状态1类状态2类状态3类状态类初始化O1O2O3返回目录7.7.1 状态模式的由来状态对象1Context类状态1类状态2类状态3类状态类Context对象如何完成状态变化?初始化O1O2O3O1返回目录7.7.1 状态模式的由来状态对象1Context类状态1类状态2类状态3类状态类Context对象如何完成状态变化?初始化Changestate()O1O2O3O1状态2类O2替换Changestate(s
47、)返回目录7.7.1 状态模式的由来状态对象1Context类状态1类状态2类状态3类状态类Context对象如何完成状态变化?初始化Changestate()O1O2O3O1状态2类O2替换Changestate(s)调用返回目录7.7.1 状态模式的由来状态对象1Context类状态1类状态2类状态3类状态类能不能保留context类的操作接口?初始化Changestate()O1O2O3O1状态2类O2替换Changestate(s)调用返回目录7.7.1 状态模式的由来状态对象1Context类状态1类状态2类状态3类状态类能不能保留context类的操作接口?初始化Changesta
48、te()O1O2O3O1状态2类O2替换Changestate(s)调用O1O2O3调用返回目录一个TCPConnection的例子返回目录7.7.2 状态模式的意图和适用性意图:让一个对象在其内部状态改变的时候,其行为也随之改变。 在下面的两种情况下均可使用S t a t e模式: 一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常, 有多个操作包含这一相同的条件结构。S t a t e模式将每一个条件分支放入一个独立的类中。这使得我们可以根据对象自身的情况
49、将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。返回目录7.7.3 状态模式的结构和参与者返回目录7.7.3 状态模式的结构和参与者 Context( (状态管理器,如状态管理器,如TCPConnection) )定义客户感兴趣的接口。,这个实例定义当前状态。 State(状态,如状态,如TCPState )定义一个接口以封装与Context的一个特定状态相关的行为。 ConcreteState subclasses(具体状态子类,如具体状态子类,如TCPEstablished, TCPListen, TCPClosed) 每一子类实现一个与Context的一个状态相关的行为
50、。返回目录7.7.4 TCPConnection代码实例 返回目录TCPConnection内部操作改变实例目标状态实例每种状态实例都具有这些操作返回目录TCPState抽象类友元操作返回目录TCPEstablished状态转移到新建listen状态静态成员实例返回目录TCPListen状态转移到新建established状态返回目录TCPClosed状态返回目录7.7.5 状态模式的效果分析n 多态性的实现class Contextpublic: a(); b(); c(); void Operation() state- Operation(this); private: friend c
51、lass State; Changestate();private: State state;class Statepublic: virtual void Operation (Context* ) = 0; protect: bool ChangeState(Context* con,State* st) con.Chagestate(st); 返回目录7.7.5 状态模式的效果分析class ConcreteStateA: public Statepublic: virtual void Operation(Context* con);protect:private:void Concr
52、eteStateA:Operation(Context* con) con.a();友元+多态返回目录7.7.5 状态模式的效果分析class ConcreteStateB: public Statepublic: virtual void Operation(Context* con);protect:private:void ConcreteStateB:Operation(Context* con) con.b();返回目录7.7.5 状态模式的效果分析class ConcreteStateC: public Statepublic: virtual void Operation(Con
53、text* con);protect:private:void ConcreteStateC:Operation(Context* con) con.c();返回目录7.7.5 状态模式的效果分析未使用STATEmain() var state; if(state=A) a(); if(state=B) b(); if(state=C) c();使用STATEmain() State state=; Context con(state); con.Operation(); 状态切换逻辑返回目录7.7.5 状态模式的效果分析n 状态的自动切换void ConcreteStateA:Operati
54、on(Context* con) con.a(); Changestate(con, new ConcreteStateB();void ConcreteStateB:Operation(Context* con) con.b(); Changestate(con, new ConcreteStateC();void ConcreteStateC:Operation(Context* con) con.c(); Changestate(con, new ConcreteStateA();使用STATEmain() State state=new ConcreteStateA(); Contex
55、t con(state); while(con.getstate()!=A); /等待起始状态A do con.Operation(); while(con.getstate()!=C); /未进入结束状态,则执行当 前状态的动作 con.Operation();返回目录7.7.5 状态模式的效果分析未使用STATEmain() var state; if(state=A) a(); state=B; if(state=B) b(); state=C; if(state=C) c(); state=A; 使用STATE模式,动作完成后,可以自动切换到下一个状态,客户无须知道具体的切换逻辑。每一
56、个ConcreteState实例只需知道本状态后可能过渡到哪些状态及相应条件即可。 传统的面向过程方法则要求用户流程的具体细节了如指掌。n 实现了与状态相关的行为的局部化 n 使用状态模式将状态的切换逻辑放到STATE的派生类中,动作的实现供派生类进行调用,实现了逻辑和动作的解耦。返回目录7.8 访问者模式(Visitor)一.访问者模式的由来二.访问者模式的意图及适用性三.访问者模式的结构及参与者四.应用举例五.效果说明AA1A2A2m()A1m()A1A2A2A1A1A1IFListi is A1 Listi.A1m()If Listi is A2 Listi.A2m()ListAccep
57、t(visitor v)AA1A2Visitor-Visit(A1 a)a.A1m()Visit(A2 a)a.A2m()Accept(visitor v) v.visit(this)A2m()Accept(visitor v) v.visit(this)A1m()A1A2A2A1A1A1Listi.accept(visitor)List返回目录7.8.1 访问者模式的由来l如何扩展一个现有的类层次结构来实现新行为?一 般的方法是给类添加新的方法。l但是万一新行为和现有对象模型不兼容怎么办?l还有,类层次结构设计人员可能无法预知以后开发 过程中将会需要哪些功能。 l还有,如果已有的类层次结构不
58、允许修改代码,怎 么能扩展行为呢? 7.8.2 访问者模式的意图和适用性l模式的意图作用于某个对象群中各个对象的操作。它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作。 返回目录7.8.2 访问者模式的意图和适用性l在下面的四种情况下均可使用Visitor模式:l1 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。l2 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。返回目录7.8.2 访问者模式的意图适用性l3 当该对象
59、结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。l4 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。返回目录7.8.3 访问者模式的结构和参与者l访问者模式结构图返回目录7.8.3 访问者模式的结构和参与者 Visitorl 访问者角色(Visitor):为该对象结构(ObjectStructure)中的具体元素提供一个访问操作接口。该操作接口的名字和参数标识了要访问的具体元素角色。这样访问者就可以通过该元素角色的特定接口直接
60、访问它。l 具体访问者角色(ConcreteVisitor):实现Vistor接口的操作。l 元素角色( Element ):该接口定义一个accept操作接受具体的访问者。l 具体元素角色(ConcreteElement):实现Element的accept操作。l 对象结构角色(ObjectStructure):这是使用访问者模式必备的角色。它要具备以下特征:能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个复合(组合模式)或是一个集合,如一个列表或一个无序集合。返回目录7.8.4 应用举例先看以下代码: public interface ITest1 /定义接口ITest1 String GetStr1();public class Test
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 房屋股份协议书范本
- 竞业协议合同范本
- 景区合作开发协议书
- 简单钢筋绑扎协议书
- 合伙建房产权协议书
- 代理商三方协议书
- 货代提单协议书
- 2025年电商代运营服务合同协议(效果承诺)
- 2025年电脑散热服务合同协议
- 2025年电竞主播直播合作合同协议
- 妊娠合并肺动脉高压的护理
- 2026年中考英语一轮复习:1600个必背词汇 话题记忆+默写本
- 2025年青少年科技创新比赛考核试卷及答案
- 光头强课件教学课件
- 杜邦安全理念培训课件
- 国企招投标管理制度
- 2025高考志愿第五轮学科评估(部分)+第四轮学科评估结果Excel表格
- DB32-T 5091-2025 超高分子量聚乙烯纤维热蠕变性能试验方法
- 环境水利学试题及答案
- 人工智能推动的兽医教育创新模式-洞察阐释
- GB/T 30134-2025冷库管理规范
评论
0/150
提交评论