第七章行為型設(shè)計模式_第1頁
第七章行為型設(shè)計模式_第2頁
第七章行為型設(shè)計模式_第3頁
第七章行為型設(shè)計模式_第4頁
第七章行為型設(shè)計模式_第5頁
已閱讀5頁,還剩193頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

1、第七章 行為型設(shè)計模式l目錄l【7.1】 模板方法模式模板方法模式(Template method) l 7.2 觀察者模式(Oberserver) 【實驗】l【7.3】 迭代子模式(Iterator) l 7.4 責(zé)任鏈模式(Chain of Responsibility)【實驗】 l 7.5 備忘錄模式(Memento) 【實驗】l 7.6 命令模式 (Command) 【實驗】l 7.7 狀態(tài)模式(State) l【7.8】 訪問者模式(訪問者模式(Visitor)l【7.9】 中介者模式(中介者模式(Mediator) l【7.10】 策略模式(策略模式(Strategy) 7.1 模

2、板方法(Template Method)模式一、模板方法模式的由來二、模板方法模式的意圖及適用性三、模板方法模式的結(jié)構(gòu)及參與者四、應(yīng)用舉例五、效果分析7.1.1 模板方法模式的由來l行為型設(shè)計模式關(guān)注的焦點之一就是類對象的職責(zé)分配,而模板方法實現(xiàn)父類和子類對象之間職責(zé)的劃分。7.1.1 模板方法模式的由來ABC類類CaC.A()7.1.1 模板方法模式的由來ABC類類CaC.A()ABCABC7.1.1 模板方法模式的由來ABC類類CaC.D()ABCABCD7.1.1 模板方法模式的由來ABC父類父類aC.D()ABCABCABCABCABCABCABCABC子類子類7.1.1 模板方法模式

3、的由來l比如就本科生如何培養(yǎng)這項工作,教育部制定綱領(lǐng)性政策,l如:軍訓(xùn)-學(xué)文化課-做畢業(yè)設(shè)計-畢業(yè)l至此,教育部的工作完成了。l接下來學(xué)生具體怎么軍訓(xùn),怎么上課,怎么做畢業(yè)設(shè)計等,就是各學(xué)校的職責(zé)了。7.1.1 模板方法模式的由來l教育部和學(xué)校之間通過上下級分工的方式分別完成了制定流程和具體實現(xiàn)2項工作。l這種思維模式引入到軟件設(shè)計中,就是Template methodlTemplate method使用繼承機制使得父類和子類之間達到分工合作的目的,父類完成流程(算法、框架),子類實現(xiàn)其具體工作。7.1.2 模板方法模式的意圖和適用性l定義一個操作中算法的骨架,將一些步驟的執(zhí)行延遲到其子類中。

4、7.1.2 模板方法模式的意圖和適用性lTemplate Method模式一般應(yīng)用在具有以下條件的應(yīng)用中:l- 具有統(tǒng)一的操作步驟或操作過程- 具有不同的操作細節(jié) 即存在多個具有同樣操作步驟的應(yīng)用場景,但某些具體的操作細節(jié)卻各不相同 模板方法模式中的兩種方法l代表這些具體邏輯步驟的方法稱做基本方法(primitive method);l將這些基本法方法總匯起來的方法叫做模版方法(template method),這摸板方法(Template Method)模式小結(jié)l 摸板方法(Template Method)模式是一種非常簡單而又經(jīng)常使用的設(shè)計模式.先創(chuàng)建一個父類,把其中的一個或多個方法留給子

5、類去實現(xiàn),這實際上就是在使用摸板模式.l 所謂的摸板模式可以這樣來理解:在一個類中定義一個算法,但將此算法的某些細節(jié)留到子類中去實現(xiàn).換句話說,基類是一個抽象類,那么你就是在使用一種簡單形式的摸板模式.l 更近一步可以這樣來理解:準(zhǔn)備一個抽象類,將部分邏輯以具體方法的形式實現(xiàn),然后申明一些抽象方法來迫使子類實現(xiàn)剩余的邏輯.不同的子類可以以不同的方法實現(xiàn)這些抽象方法,從而對剩余的邏輯有不同的實現(xiàn).7.1.3 模板方法模式的結(jié)構(gòu)和參與者7.1.3 模板方法模式的結(jié)構(gòu)和參與者1)AbstractClass, 定義抽象的原語操作,具體子類將重定義他們以實現(xiàn)一個算法的各步驟 實現(xiàn)一個模板方法,定義一個算

6、法的骨架。該模板不僅調(diào)用原語操作,也調(diào)用定義在AbstractClass或其他對象中的操作2)ConcreteClass 實現(xiàn)原語操作以完成算法中與特定子類相關(guān)的步驟教材上的應(yīng)用舉例l取款單模板l.4 應(yīng)用舉例l就前面所舉的本科生培養(yǎng)的例子,給出其代碼實現(xiàn)的示例。l看看如何實現(xiàn)父類與子類的分工,即教育部本科生培養(yǎng)處與各高校的本科生培養(yǎng)處如何實現(xiàn)職責(zé)劃分7.1.4 應(yīng)用舉例l public abstract class 教育部本科生培養(yǎng)處 /這就是一個,定義了算法的骨架 public void 本科生培養(yǎng)() l 軍訓(xùn)(); 上課(); 畢業(yè)設(shè)計(); 授予學(xué)位(); /這里還可

7、以有其它培養(yǎng)內(nèi)容l protected abstract void 軍訓(xùn)(); protected abstract void 上課(); protected abstract void 畢業(yè)設(shè)計(); protected abstract void 授予學(xué)位(); 7.1.4 應(yīng)用舉例 public class 清華大學(xué)本科生培養(yǎng)處 : 教育部本科生培養(yǎng)處 protected override void 軍訓(xùn)() /站軍姿l /正步走 protected override void 上課() /具體課程l protected override 畢業(yè)設(shè)計() /開題,論文,答辯l protec

8、ted override 授予() /授予儀式 7.1.4 應(yīng)用舉例l public class App l l static void Main() l l 教育部本科生培養(yǎng)處 PYC=new 清華大學(xué)本科生培養(yǎng)處();l PYC.本科生培養(yǎng)();l Console.Read(); /等待用戶輸入 l 實用例子lHttpServlet技術(shù)l造電腦的示例l數(shù)據(jù)庫訪問的模板方法l有趣的模板方法模式:造悍馬汽車7.1.5 效果分析l模板方法是一種代碼復(fù)用技術(shù),提取了“子類”的公共行為l模板方法導(dǎo)致一種反向的控制結(jié)構(gòu):“你別來找我,讓我去找你”,即:一個父類調(diào)用子類的操作,而不是相反。關(guān)于繼承的討論

9、l模版方法模式鼓勵恰當(dāng)?shù)厥褂美^承。此模式可以用來改寫一些擁有相同功能的相關(guān)的類,將可復(fù)用的l一般性的行為代碼移到基類里面,而把特殊化的行為代碼移到子類里面。l因此,熟悉模版方法模式便成為一個重新學(xué)習(xí)繼承的好地方。7.2 觀察者模式(Oberserver) 【實驗】 一.觀察者模式的由來二.觀察者模式的意圖及適用性三.觀察者模式的結(jié)構(gòu)及參與者四.應(yīng)用舉例五.效果說明7.2.1 觀察者模式的由來l在制作系統(tǒng)的過程中,將一個系統(tǒng)分割成一系列相互協(xié)作的類有一個常見的副作用:需要維護相關(guān)對象間的一致性。我們不希望為了維持一致性而使各類緊密耦合,因為這樣降低了他們的可充用性。7.2.1 觀察者模式的由來

10、例如, 許多圖形用戶界面工具箱將用戶應(yīng)用的界面表示與底下的應(yīng)用數(shù)據(jù)分離。定義應(yīng)用數(shù)據(jù)的類和負責(zé)界面表示的類可以各自獨立地復(fù)用。當(dāng)然它們也可一起工作。一個表格對象和一個柱狀圖對象可使用不同的表示形式描述同一個應(yīng)用數(shù)據(jù)對象的信息。表格對象和柱狀圖對象互相并不知道對方的存在,這樣使你可以根據(jù)需要單獨復(fù)用表格或柱狀圖。但在這里是它們表現(xiàn)的似乎互相知道。當(dāng)用戶改變表格中的信息時,柱狀圖能立即反映這一變化, 反過來也是如此。7.2.1 觀察者模式的由來 這一行為意味著表格對象和棒狀圖對象都依賴于數(shù)據(jù)對象, 因此數(shù)據(jù)對象的任何狀態(tài)改變都應(yīng)立即通知它們。同時也沒有理由將依賴于該數(shù)據(jù)對象的對象的數(shù)目限定為兩個,

11、 對相同的數(shù)據(jù)可以有任意數(shù)目的不同用戶界面。7.2.2 觀察者模式的意圖和適用性l模式的意圖 定義對象間的一種一對多的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新。 7.2.2 觀察者模式的意圖和適用性l 在下面的三種情況下均可使用Observer模式:l 當(dāng)一個抽象模型有兩個方面, 其中一個方面依賴于另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立地改變和復(fù)用。l 當(dāng)對一個對象的改變需要同時改變其它對象, 而不知道具體有多少對象有待改變。l 當(dāng)一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之, 你不希望這些對象是緊密耦合的。7.2.3 觀

12、察者模式的結(jié)構(gòu)和參與者l觀察者模式結(jié)構(gòu)圖7.2.3 觀察者模式的結(jié)構(gòu)和參與者 Observerl Subject(目標(biāo)) 目標(biāo)知道它的觀察者??梢杂腥我舛鄠€觀察者觀察同一個目標(biāo)。 提供注冊和刪除觀察者對象的接口。l Observer(觀察者) 為那些在目標(biāo)發(fā)生改變時需獲得通知的對象定義一個更新接口。l Concrete Subject(具體目標(biāo)) 將有關(guān)狀態(tài)存入各Concrete Observer對象。 當(dāng)它的狀態(tài)發(fā)生改變時, 向它的各個觀察者發(fā)出通知。l Concrete Observer(具體觀察者) 維護一個指向Concrete Subject對象的引用。 存儲有關(guān)狀態(tài),這些狀態(tài)應(yīng)與目標(biāo)

13、的狀態(tài)保持一致。 實現(xiàn)Observer的更新接口以使自身狀態(tài)與目標(biāo)的狀態(tài)保持一致。7.2.4 應(yīng)用舉例 例如:班主任老師有電話號碼,學(xué)生需要知道班主任老師的電話號碼以便于在合適時的時候撥打,在這樣的組合中,老師就是一個被觀察者(Subject),學(xué)生就是需要知道信息的觀察者,當(dāng)老師的電話號碼發(fā)生改變時,學(xué)生得到通知,并更新相應(yīng)的電話記錄。該應(yīng)用的類圖如下圖所示。應(yīng)用舉例7.2.4 應(yīng)用舉例相關(guān)代碼:Subject代碼:package observer; public interface Subject /目標(biāo)類的定義public void attach(Observer o); /注冊一個觀察

14、者public void detach(Observer o); /刪除一個觀察者public void notice(); /通知所有觀察者更新Observer代碼:package observer;public interface Observer /觀察者類定義public void update(); /更新觀察者7.2.4 應(yīng)用舉例Teacher代碼;package observer;import java.util.Vector;public class Teacher implements Subjectprivate String phone; /電話號碼private Vec

15、tor students; /學(xué)生public Teacher()phone = ;students = new Vector();public void attach(Observer o)students.add(o);/注冊學(xué)生public void detach(Observer o)students.remove(o);刪除學(xué)生public void notice() /通知學(xué)生更新 for(int i=0;istudents.size();i+) (Observer)students.get(i).update();public void setPhone(String phone

16、)this.phone = phone;notice();public String getPhone()return phone;7.2.4 應(yīng)用舉例Student代碼:package observer;public class Student implements Observerprivate String name; /學(xué)生姓名private String phone; /班主任老師電話private Teacher teacher;public Student(String name,Teacher t) = name;teacher = t;public void

17、 show()System.out.println(Name:+name+nTeachers phone:+phone);public void update() /更新電話號碼與老師的保持一致phone = teacher.getPhone(); 7.2.4 應(yīng)用舉例 Client代碼:package observer;import java.util.Vector;public class Clientpublic static void main(String args)Vector students = new Vector(); /定義學(xué)生類向量Teacher t = new Tea

18、cher(); /定義老師類對象for(int i= 0 ;i10;i+) Student st = new Student(lili+i,t); students.add(st); /把學(xué)生加到向量中 t.attach(st); /老師注冊一個學(xué)生t.setPhone(“123);for(int i=0;i10;i+) (Student)students.get(i).show(); /所有學(xué)生的老師電話都為123t.setPhone(“456);for(int i=0;i10;i+) (Student)students.get(i).show(); /所有學(xué)生的老師電話都為4567.2.5

19、 效果分析觀察者模式的應(yīng)用場景:l對一個對象狀態(tài)的更新,需要其他對象同步更新,而且其他對象的數(shù)量動態(tài)可變。l對象僅需要將自己的更新通知給其他對象而不需要知道其他對象的細節(jié)。7.2.5 效果分析觀察者模式的優(yōu)點:lSubject和Observer之間是松偶合的,分別可以各自獨立改變。lSubject在發(fā)送廣播通知的時候,無須指定具體的Observer,Observer可以自己決定是否要訂閱Subject的通知。l遵守大部分GRASP原則和常用設(shè)計原則,高內(nèi)聚、低偶合。7.2.5 效果分析觀察者模式的缺陷:l松偶合導(dǎo)致代碼關(guān)系不明顯,有時可能難以理解。l如果一個Subject被大量Observer

20、訂閱的話,在廣播通知的時候可能會有效率問題。7.3迭代子模式(Iterator)一、迭代子模式的由來二、迭代子模式的意圖及適用性三、迭代子模式的結(jié)構(gòu)及參與者四、應(yīng)用舉例五、效果分析7.3.1 迭代子模式的由來l 以集合對象為例,集合是一個管理和組織數(shù)據(jù)對象的數(shù)據(jù)結(jié)構(gòu)。這就表明集合首先應(yīng)具備一個基本屬性,就是集合能夠存儲數(shù)據(jù)。這其中包含存儲數(shù)據(jù)的類型、存儲空間的大小、存儲空間的分配、以及存儲的方式和順序。不具備這些特點,則該對象就不成其為集合對象。也就是說,上述這些屬性是集合對象與身俱來的,是其密不可分的職責(zé)。l 然而,集合對象除了能夠存儲數(shù)據(jù)外,還必須提供訪問其內(nèi)部數(shù)據(jù)的行為方式,這是一種遍歷

21、機制。同時這種遍歷方式,或會根據(jù)不同的情形提供不同的實現(xiàn),如順序遍歷,逆序遍歷,或是二叉樹結(jié)構(gòu)的中序、前序、后序遍歷。7.3.1 迭代子模式的由來順序逆序中序后序存儲 聚合類遍歷機制7.3.1 迭代子模式的由來順序逆序中序后序存儲 迭代類聚合類7.3.1 迭代子模式的由來l 迭代子模式實際上做的工作就是把對象的職責(zé)分離。職責(zé)分離,可以最大限度地減少彼此之間的耦合程度,從而建立一個松散耦合的對象網(wǎng)絡(luò)。l 職責(zé)分離的要點是對被分離的職責(zé)進行封裝,并以抽象的方式建立起彼此之間的關(guān)系。例如,我們往往將這些可能變化的對象抽象為接口和抽象類,從而將原來的具體依賴改變?yōu)槌橄笠蕾?。對象不再受制于具體的實現(xiàn)細節(jié)

22、約束7.3.1 迭代子模式的由來l現(xiàn)在我們已經(jīng)分辨出集合對象擁有的兩個職責(zé):一是存儲內(nèi)部數(shù)據(jù);二是遍歷內(nèi)部數(shù)據(jù)。從依賴性來看,前者為集合對象的根本屬性,而后者既是可變化的,又是可分離的。因此,我們將遍歷行為分離出來,抽象為一個迭代器,專門提供遍歷集合內(nèi)部數(shù)據(jù)對象的行為。這就是迭代子模式的本質(zhì)。7.3.2 迭代子模式的意圖和適用性l模式的意圖 迭代子模式的目的是設(shè)計一個迭代器,這迭代器提供一種方法,可以順序訪問一個聚合對象中的各個元素,但又不暴露該對象的內(nèi)部表示7.3.2 迭代子模式的意圖和適用性l以下情況可以使用迭代子模式:l1.訪問一個聚合對象的內(nèi)容而無需暴露它的內(nèi)部表示。l2.支持對聚合對

23、象的多種遍歷。l3.為遍歷不同的聚合結(jié)構(gòu)提供一個統(tǒng)一的接口 (即, 支持多態(tài)迭代)。7.3.3 迭代子模式的結(jié)構(gòu)和參與者l迭代子模式結(jié)構(gòu)圖7.3.3 迭代子模式的結(jié)構(gòu)和參與者l 迭代器迭代器(Iterator) 迭代器定義訪問和遍歷元素的接口。l 具體迭代器具體迭代器(ConcreteIterator)1.具體迭代器實現(xiàn)迭代器接口。2.對該聚合遍歷時跟蹤當(dāng)前位置。l 聚合聚合(Aggregate)聚合定義創(chuàng)建相應(yīng)迭代器對象的接口。l 具體聚合具體聚合(ConcreteAggregate)具體聚合實現(xiàn)創(chuàng)建相應(yīng)迭代器的接口,該操作返回 具體迭代器 的一個適當(dāng)?shù)膶嵗?.3.4 應(yīng)用舉例兩種實現(xiàn)方式

24、l 1 白箱聚集與外稟迭代子:白箱聚集向外界提供訪問自己內(nèi)部元素的接口,從而使得外稟迭代子,可以通過聚集提供的方法實現(xiàn)迭代功能。l 2 黑箱聚集內(nèi)稟迭代子:黑箱聚集不向外界提供遍歷自己的元素的接口,因此聚集的成員只能被聚集內(nèi)部的方法訪問。由于內(nèi)稟迭代子恰好是聚集的成員,因此可以訪問聚集元素。應(yīng)用舉例之白箱例子Aggregate:abstract public class Aggregate public Iterator createIterator() return null; Iterator:public interface Iterator void first(); void nex

25、t(); bool isDone(); Object currentItem();Aggregateiterator思考:兩者如何連接應(yīng)用舉例之白箱例子AggregateiteratorcreateIterator()Aggregate應(yīng)用舉例之白箱例子public class ConcreteAggregate : Aggregate private Object objs = Monk Tang , Monkey, Pigsy, Sandy”; public Iterator createIterator() return new ConcreteIterator(this); publi

26、c Object getElement(int index) if(index objs.Length) return objsindex; else return null; public int size() return objs.Length; createIterator() ConcreteAggregatepublic class ConcreteIterator implements Iterator private ConcreteAggregate agg; private int index = 0; private int size = 0; public Concre

27、teIterator(ConcreteAggregate agg) this.agg = agg; size = agg.size(); index = 0 ; public 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; privat

28、e Aggregate agg = new ConcreteAggregate();public void operation() it = agg.createIterator(); while( !it.isDone() ) System.out.println(it.currentItem().toString(); it.next(); public static void main(String args) Client client = new Client(); client.operation(); 應(yīng)用舉例之白箱例子createIterator() ConcreteAggre

29、gate迭代類聚合類Firstnext應(yīng)用舉例之黑箱例子Iterator:public interface Iterator void first(); void next(); boolean isDone(); Object currentItem();Aggregate:abstract public class Aggregate public Iterator createIterator() return null; ConcreteAggregate:public class ConcreteAggregate extends Aggregate private Object o

30、bjs = Monk Tang,Monkey, Pigs,Sandy, Horse; public Iterator createIterator() 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

31、= 20 & request 30 ) Console.WriteLine(0 handled request 1, this, 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 =

32、new ConcreteHandler2(); Handler h3 = new ConcreteHandler3(); h1.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 責(zé)任鏈模式并不創(chuàng)建責(zé)任鏈。責(zé)任鏈的創(chuàng)建必須由系統(tǒng)的其它部分創(chuàng)建出來。l 責(zé)任鏈模式降低了請求的發(fā)送端和接收端之

33、間的耦合,使多個對象都有機會處理這個請求。一個鏈可以是一條線,一個樹,也可以是一個環(huán)。如下圖所示,責(zé)任鏈?zhǔn)且粋€樹結(jié)構(gòu)的一部分。1) 優(yōu)點:責(zé)任鏈模式的最大的一個有點就是給系統(tǒng)降低了耦合性,請求的發(fā)送者完全不必知道該請求會被哪個應(yīng)答對象處理,極大地降低了系統(tǒng)的耦合性。 2) 缺點:消息傳遞和處理不當(dāng)會出現(xiàn)消息的循環(huán)重復(fù)執(zhí)行。7.4.5 效果分析7.5 備忘錄模式(Memento) 【實驗】一、備忘錄模式的由來二、備忘錄模式的意圖及適用性三、備忘錄模式的結(jié)構(gòu)及參與者四、應(yīng)用舉例五、效果分析7.5.1 備忘錄模式的由來l沒有人想犯錯誤,但是沒有人能夠不犯錯誤。犯了錯誤一般只能改過,卻很難改正(恢復(fù))

34、。世界上沒有后悔藥,但是我們在進行軟件系統(tǒng)的設(shè)計時候是要給用戶后悔的權(quán)利(實際上可能也是用戶要求的權(quán)利),我們對一些關(guān)鍵性的操作肯定需要提供諸如撤銷 (Undo)的操作。那這個后悔藥就是 Memento 模式提供的。7.5.2 備忘錄模式的意圖和適用性模式的意圖 在不破壞封裝性的前提下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài)。這樣以后就可將該對象恢復(fù)到原先保存的狀態(tài)7.5.2 備忘錄模式的意圖和適用性在以下情況下使用備忘錄模式:l必須保存一個對象在某一個時刻的 (部分)狀態(tài), 這樣以后需要時它才能恢復(fù)到先前的狀態(tài)。l如果一個用接口來讓其它對象直接得到這些狀態(tài),將會暴露對象的實現(xiàn)細節(jié)

35、并破壞對象的封裝性。7.5.3備忘錄模式的結(jié)構(gòu)和參與者備忘錄模式結(jié)構(gòu)圖:7.5.3 備忘錄模式的結(jié)構(gòu)和參與者:1) 備忘錄(Memento):備忘錄存儲原發(fā)器對象的內(nèi)部狀態(tài);防止原發(fā)器以外的其他對象訪問備忘錄。2) 原發(fā)器(Originator):原發(fā)器創(chuàng)建一個備忘錄,用以記錄當(dāng)前時刻它的內(nèi)部狀態(tài);使用備忘錄恢復(fù)內(nèi)部狀態(tài)。/Originatorclass Originator public: typedef string State; Originator(); Originator(const State& sdt); Originator(); Memento* CreateMem

36、ento(); void SetMemento(Memento* men); void RestoreToMemento(Memento* mt); State GetState(); void SetState(const State& sdt); void PrintState(); private: State _sdt; Memento* _mt; ; 7.5.4 應(yīng)用舉例Originator:Originator() _sdt = ; _mt = 0; Originator:Originator(const State& sdt) _sdt = sdt; _mt =

37、0; Originator:Originator() 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 Origin

38、ator; /這是最關(guān)鍵的地方,將Originator為friend類,可以訪問內(nèi)部信息,但是其他類不能訪問 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) _s

39、dt = sdt; State 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”); /備忘前狀態(tài) o-PrintState(); Memento* m = o-CreateMemento(); /將狀態(tài)備忘 o-SetState(“new”); /修改狀態(tài) o-PrintState();

40、o-RestoreToMemento(m); /恢復(fù)修改前狀態(tài) o-PrintState(); return 0; 優(yōu)點:1)保持封裝邊界;使用備忘錄可以避免暴露一些只應(yīng)由原發(fā)器管理卻又必須存儲在原發(fā)器之外的信息。該模式把可能很復(fù)雜的原發(fā)器內(nèi)部信息對其他對象屏蔽起來,從而保持了封裝邊界。2)簡化原發(fā)器;在其他的保持封裝性的設(shè)計中 ,原發(fā)器負責(zé)保持客戶請求過的內(nèi)部狀態(tài)版本。這就把所有存儲管理的重任交給了原發(fā)器。讓客戶管理它們請求的狀態(tài)將會簡化原發(fā)器,并且使得客戶工作結(jié)束時無需通知原發(fā)器。缺點:1)定義窄接口和寬接口;在一些語言中可能難以保證只有原發(fā)器可訪問備忘錄的狀態(tài)。2)使用備忘錄可能代價很高

41、;如果原發(fā)器在生成備忘錄時必須拷貝并存儲大量的信息 ,或者客戶非常頻繁地創(chuàng)建備忘錄和恢復(fù)原發(fā)器狀態(tài),可能會導(dǎo)致非常大的開銷。除非封裝和恢復(fù)原發(fā)器狀態(tài)的開銷不大,否則該模式可能并不合適。7.5.5 效果分析7.6 命令模式 (Command) 【實驗】一.命令模式的由來二.模式意圖和適用性三.模式結(jié)構(gòu)和參與者四. 實例說明五. 效果分析7.6.1 命令模式的由來 將一個請求封裝為一個對象,從而使我們可用不同的請求對客戶進行參數(shù)化;對請求排隊或記錄請求日志,以及支持可撤消的操作。一個菜單控件的例子PasteCommand命令OpenCommand命令MacroCommand命令腳本7.6.3 命令

42、模式的意圖和適用性意圖:l將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數(shù)化;對請求排隊或記錄請求日志,以及支持可取消的操作 7.6.3 命令模式的意圖和適用性適用性:抽象出待執(zhí)行的動作以參數(shù)化某對象在不同的時刻指定、排列和執(zhí)行請求支持取消操作(Unexecute)支持修改日志用構(gòu)建在原語操作上的高層操作構(gòu)造一個系統(tǒng)7.6.4 命令模式的結(jié)構(gòu)和參與者7.6.4 命令模式的結(jié)構(gòu)和參與者Commandu聲明執(zhí)行操作的接口ConcreteCommandu將一個接收者對象綁定于一個動作u調(diào)用接收者相應(yīng)的操作,以實現(xiàn)ExecuteClient(Application)u創(chuàng)建一個具體命令對象

43、并設(shè)定它的接收者Invoker(MenuItem)u要求該命令執(zhí)行這個請求Receiver(Document,Application) u知道如何實施與執(zhí)行一個請求相關(guān)的操作7.6.4 應(yīng)用舉例菜單控件的代碼實例Command抽象類OpenCommand命令PasteCommand命令7.6.5 命令模式效果分析Command模式將調(diào)用操作的對象與知道如何實現(xiàn)該操作的對象解耦Command是頭等 的對象,它們可像其他的對象一樣被操縱和擴展可將多個命令裝配成一個復(fù)合命令可以很容易的增加新的Command對象,因為這無需改變已有的類。7.7 狀態(tài)模式(State)一.模式的由來二.狀態(tài)狀態(tài)模式的意

44、圖及適用性三.狀態(tài)模式的結(jié)構(gòu)及參與者四.應(yīng)用舉例五.效果說明7.7.1 狀態(tài)模式的由來 一個對象有多種狀態(tài),在不同的狀態(tài)下,對象可以有不同的行為。7.7.1 狀態(tài)模式的由來狀態(tài)變量sSwitch s Case 1 do o1 s=3 Case 2 do o2 s=2 End switchContext類初始狀態(tài)1狀態(tài)變化:13 2思考:缺陷在哪里?O1O2O3操作7.7.1 狀態(tài)模式的由來Context類狀態(tài)1類狀態(tài)2類狀態(tài)3類狀態(tài)類思考:兩者如何連接?O1O2O37.7.1 狀態(tài)模式的由來狀態(tài)對象Context類狀態(tài)1類狀態(tài)2類狀態(tài)3類狀態(tài)類初始化思考:狀態(tài)操作放在哪里?O1O2O37.7.

45、1 狀態(tài)模式的由來狀態(tài)對象Context類狀態(tài)1類狀態(tài)2類狀態(tài)3類狀態(tài)類初始化O1O2O37.7.1 狀態(tài)模式的由來狀態(tài)對象1Context類狀態(tài)1類狀態(tài)2類狀態(tài)3類狀態(tài)類Context對象如何完成狀態(tài)變化?初始化O1O2O3O17.7.1 狀態(tài)模式的由來狀態(tài)對象1Context類狀態(tài)1類狀態(tài)2類狀態(tài)3類狀態(tài)類Context對象如何完成狀態(tài)變化?初始化Changestate()O1O2O3O1狀態(tài)3類O3替換Changestate(s)7.7.1 狀態(tài)模式的由來狀態(tài)對象1Context類狀態(tài)1類狀態(tài)2類狀態(tài)3類狀態(tài)類Context對象如何完成狀態(tài)變化?初始化Changestate()O1O2O

46、3O1狀態(tài)3類O3替換Changestate(s)調(diào)用思考:O1有沒有權(quán)調(diào)用changestate()7.7.1 狀態(tài)模式的由來狀態(tài)對象1Context類狀態(tài)1類狀態(tài)2類狀態(tài)3類狀態(tài)類初始化Changestate()O1O2O3O1狀態(tài)2類O2替換Changestate(s)調(diào)用能不能保留context類的o1,o2,o3操作接口?以支持兼容7.7.1 狀態(tài)模式的由來狀態(tài)對象1Context類狀態(tài)1類狀態(tài)2類狀態(tài)3類狀態(tài)類能不能保留context類的o1,o2,o3操作接口?以支持兼容初始化Changestate()O1O2O3O1狀態(tài)2類O2替換Changestate(s)調(diào)用O1O2O3調(diào)

47、用一個TCPConnection的例子7.7.2 狀態(tài)模式的意圖和適用性意圖:讓一個對象在其內(nèi)部狀態(tài)改變的時候,其行為也隨之改變。 在下面的兩種情況下均可使用S t a t e模式: 一個對象的行為取決于它的狀態(tài), 并且它必須在運行時刻根據(jù)狀態(tài)改變它的行為。 一個操作中含有龐大的多分支的條件語句,且這些分支依賴于該對象的狀態(tài)。這個狀態(tài)通常用一個或多個枚舉常量表示。通常, 有多個操作包含這一相同的條件結(jié)構(gòu)。S t a t e模式將每一個條件分支放入一個獨立的類中。這使得我們可以根據(jù)對象自身的情況將對象的狀態(tài)作為一個對象,這一對象可以不依賴于其他對象而獨立變化。7.7.3 狀態(tài)模式的結(jié)構(gòu)和參與者7

48、.7.3 狀態(tài)模式的結(jié)構(gòu)和參與者 Context( (狀態(tài)管理器,如狀態(tài)管理器,如TCPConnection) )定義客戶感興趣的接口。,這個實例定義當(dāng)前狀態(tài)。 State(狀態(tài),如狀態(tài),如TCPState )定義一個接口以封裝與Context的一個特定狀態(tài)相關(guān)的行為。 ConcreteState subclasses(具體狀態(tài)子類,如具體狀態(tài)子類,如TCPEstablished, TCPListen, TCPClosed) 每一子類實現(xiàn)一個與Context的一個狀態(tài)相關(guān)的行為。7.7.4 TCPConnection代碼實例 TCPConnection內(nèi)部操作改變實例目標(biāo)狀態(tài)實例每種狀態(tài)實例都

49、具有這些操作TCPState抽象類友元操作TCPEstablished狀態(tài)轉(zhuǎn)移到新建listen狀態(tài)靜態(tài)成員實例TCPListen狀態(tài)轉(zhuǎn)移到新建established狀態(tài)TCPClosed狀態(tài)7.7.5 狀態(tài)模式的效果分析n 多態(tài)性的實現(xiàn)class Contextpublic: a(); b(); c(); void Operation() state- Operation(this); private: friend class State; Changestate();private: State state;class Statepublic: virtual void Operatio

50、n (Context* ) = 0; protect: bool ChangeState(Context* con,State* st) con.Chagestate(st); 7.7.5 狀態(tài)模式的效果分析class ConcreteStateA: public Statepublic: virtual void Operation(Context* con);protect:private:void ConcreteStateA:Operation(Context* con) con.a();友元+多態(tài)7.7.5 狀態(tài)模式的效果分析class ConcreteStateB: public

51、Statepublic: virtual void Operation(Context* con);protect:private:void ConcreteStateB:Operation(Context* con) con.b();7.7.5 狀態(tài)模式的效果分析class ConcreteStateC: public Statepublic: virtual void Operation(Context* con);protect:private:void ConcreteStateC:Operation(Context* con) con.c();7.7.5 狀態(tài)模式的效果分析未使用ST

52、ATEmain() var state; if(state=A) a(); if(state=B) b(); if(state=C) c();使用STATEmain() State state=; Context con(state); con.Operation(); 狀態(tài)切換邏輯7.7.5 狀態(tài)模式的效果分析n 狀態(tài)的自動切換void ConcreteStateA:Operation(Context* con) con.a(); Changestate(con, new ConcreteStateB();void ConcreteStateB:Operation(Context* con)

53、 con.b(); Changestate(con, new ConcreteStateC();void ConcreteStateC:Operation(Context* con) con.c(); Changestate(con, new ConcreteStateA();使用STATEmain() State state=new ConcreteStateA(); Context con(state); while(con.getstate()!=A); /等待起始狀態(tài)A do con.Operation(); while(con.getstate()!=C); /未進入結(jié)束狀態(tài),則執(zhí)行

54、當(dāng) 前狀態(tài)的動作 con.Operation();7.7.5 狀態(tài)模式的效果分析未使用STATEmain() var state; if(state=A) a(); state=B; if(state=B) b(); state=C; if(state=C) c(); state=A; 使用STATE模式,動作完成后,可以自動切換到下一個狀態(tài),客戶無須知道具體的切換邏輯。每一個ConcreteState實例只需知道本狀態(tài)后可能過渡到哪些狀態(tài)及相應(yīng)條件即可。 傳統(tǒng)的面向過程方法則要求用戶流程的具體細節(jié)了如指掌。n 實現(xiàn)了與狀態(tài)相關(guān)的行為的局部化 n 使用狀態(tài)模式將狀態(tài)的切換邏輯放到STATE的派

55、生類中,動作的實現(xiàn)供派生類進行調(diào)用,實現(xiàn)了邏輯和動作的解耦。7.8 訪問者模式(Visitor)一.訪問者模式的由來二.訪問者模式的意圖及適用性三.訪問者模式的結(jié)構(gòu)及參與者四.應(yīng)用舉例五.效果說明AA1A2A2m()A1m()A1A2A2A1A1A1IFListi is A1 Listi.A1m()If Listi is A2 Listi.A2m()ListAA1A2A2m()A1m()A1A2A2A1A1A1Listi.Am()List思考:能不能有一個統(tǒng)一的訪問方法?某位同學(xué)的解決辦法Ma(A *a) if a is A1 a.a1m() if a is A2 a.a2m Ma() a1(

56、)A1m()Ma()A2m()A2m()AA1A2A1A2A2A1A1A1Listi.ma(this)List思考:這樣做的缺陷?Ma()Ma()A3m()A3m()A3Class visitor visit(A1 a) a.a1m() visit(A2 a) a.a2m Ma()A1m()Ma()A2m()AA1A2A1A2A2A1A1A1Listi.Am(this)List思考:這樣做的缺陷?Ma(A *a) ? 抽象AA1A2Visitor-Visit(A1 a)a.A1m()Visit(A2 a)a.A2m()Accept(visitor v) v.visit(this)A1m()A1

57、A2A2A1A1A1Listi.accept(visitor)List7.8.1 訪問者模式的由來l如何擴展一個現(xiàn)有的類層次結(jié)構(gòu)來實現(xiàn)新行為?一 般的方法是給類添加新的方法。l但是萬一新行為和現(xiàn)有對象模型不兼容怎么辦?l還有,類層次結(jié)構(gòu)設(shè)計人員可能無法預(yù)知以后開發(fā) 過程中將會需要哪些功能。 l還有,如果已有的類層次結(jié)構(gòu)不允許修改代碼,怎 么能擴展行為呢? 7.8.2 訪問者模式的意圖和適用性l模式的意圖作用于某個對象群中各個對象的操作。它可以使你在不改變這些對象本身的情況下,定義作用于這些對象的新操作。 7.8.2 訪問者模式的意圖和適用性l在下面的四種情況下均可使用Visitor模式:l1

58、一個對象結(jié)構(gòu)包含很多類對象,它們有不同的接口,而你想對這些對象實施一些依賴于其具體類的操作。l2 需要對一個對象結(jié)構(gòu)中的對象進行很多不同的并且不相關(guān)的操作,而你想避免讓這些操作“污染”這些對象的類。Visitor使得你可以將相關(guān)的操作集中起來定義在一個類中。7.8.2 訪問者模式的意圖適用性l3 當(dāng)該對象結(jié)構(gòu)被很多應(yīng)用共享時,用Visitor模式讓每個應(yīng)用僅包含需要用到的操作。l4 定義對象結(jié)構(gòu)的類很少改變,但經(jīng)常需要在此結(jié)構(gòu)上定義新的操作。改變對象結(jié)構(gòu)類需要重定義對所有訪問者的接口,這可能需要很大的代價。如果對象結(jié)構(gòu)類經(jīng)常改變,那么可能還是在這些類中定義這些操作較好。7.8.3 訪問者模式的

59、結(jié)構(gòu)和參與者l訪問者模式結(jié)構(gòu)圖7.8.3 訪問者模式的結(jié)構(gòu)和參與者 Visitorl 訪問者角色(Visitor):為該對象結(jié)構(gòu)(ObjectStructure)中的具體元素提供一個訪問操作接口。該操作接口的名字和參數(shù)標(biāo)識了要訪問的具體元素角色。這樣訪問者就可以通過該元素角色的特定接口直接訪問它。l 具體訪問者角色(ConcreteVisitor):實現(xiàn)Vistor接口的操作。l 元素角色( Element ):該接口定義一個accept操作接受具體的訪問者。l 具體元素角色(ConcreteElement):實現(xiàn)Element的accept操作。l 對象結(jié)構(gòu)角色(ObjectStructur

60、e):這是使用訪問者模式必備的角色。它要具備以下特征:能枚舉它的元素;可以提供一個高層的接口以允許該訪問者訪問它的元素;可以是一個復(fù)合(組合模式)或是一個集合,如一個列表或一個無序集合。7.8.4 應(yīng)用舉例先看以下代碼: public interface ITest1 /定義接口ITest1 String GetStr1();public class Test1:ITest1 /Test1實現(xiàn)接口ITest1 public String GetStr1() return “Test1”;public interface ITest2 /定義接口ITest2 String GetStr2();public class Test2:ITest2 /Test2實現(xiàn)接口ITest

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論