C++設(shè)計(jì)模式第六講_第1頁(yè)
C++設(shè)計(jì)模式第六講_第2頁(yè)
C++設(shè)計(jì)模式第六講_第3頁(yè)
C++設(shè)計(jì)模式第六講_第4頁(yè)
C++設(shè)計(jì)模式第六講_第5頁(yè)
已閱讀5頁(yè),還剩13頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、C+設(shè)計(jì)模式教程第六講:UIPPaint設(shè)計(jì)模式(分析篇) (中間者、門(mén)面、狀態(tài)、命令、訪問(wèn)者、職責(zé)鏈設(shè)計(jì)模式)主講人:步磊峰 UIPower 3D界面引擎負(fù)責(zé)人前言:UIPPaint需求描述2 第一節(jié):UIPPaint需求分析-需要哪些控件3 這是一個(gè)比較簡(jiǎn)單的程序,如果我們根據(jù)需求,直接編碼的話,可能很快就會(huì)實(shí)現(xiàn)所有功能。 但是這不是我們的目的。我們要使用各種合適的設(shè)計(jì)模式,降低代碼的耦合性,使其非常容易擴(kuò)展,在添加功能的時(shí) 候,不需要修改很多代碼。歸根結(jié)底,我們要根據(jù)需求實(shí)現(xiàn)一個(gè)可擴(kuò)展,容易修改,低耦合性的框架。 那么我們來(lái)分析需求,提出設(shè)計(jì)思路: 1) UIPLib僅提供了CContr

2、olBase基類,封裝了一些不變的流程,但是并沒(méi)有提供實(shí)際的繪圖功能,需要我們自己實(shí) 現(xiàn)具體的控件。根據(jù)前面的需求,我們發(fā)現(xiàn)我們需要一個(gè)Button控件,表現(xiàn)形式如同CheckBox類型,當(dāng)多個(gè)Butt on在同一組時(shí),有且只有一個(gè)處于選中狀態(tài)。當(dāng)一組Button某個(gè)按鈕被選中時(shí),要觸發(fā)Selected為true的事件, 而與此同時(shí),同組的其他Button觸發(fā)Selected為false的事件(Unselected)。選中時(shí)使用一個(gè)Icon,未選中時(shí)使 用另外一個(gè)Icon,以區(qū)分這兩種狀態(tài)。 我們編寫(xiě)CIconButton控件用于上述用途。實(shí)際上CIconButton區(qū)分是否 是toggle類

3、型Button(符合上述需求)和非toggle類型Button(鼠標(biāo)按下使用一種Icon,鼠標(biāo)彈起使用另外一種 Icon)。 第一節(jié):UIPPaint需求分析-需要哪些控件4 2) 需要另外一個(gè)控件CPaintArea,表示一個(gè)可繪制的區(qū)域。它會(huì)繪制邊框和背景色。 為了支持圖元對(duì)象的繪制(CShapeBase的子類,在本Demo中是CRectShape,CCircleShape,CTriangleShape), 我們?cè)贑PaintArea中override 受保護(hù)的虛函數(shù)OnRender,并在最后觸發(fā)CRenderEvent事件: 為了簡(jiǎn)單起見(jiàn),我們同時(shí)使用CPaintArea作為左側(cè)工具按鈕

4、集合的父親,這樣將toggle按鈕以CPaintArea為父親分成一組: 第二節(jié):UIPPaint需求分析-狀態(tài)模式5根據(jù)需求: 當(dāng)我們鼠標(biāo)點(diǎn)中某個(gè)IconButton時(shí),會(huì)觸發(fā)Selected為true的事件,或許我們可以直接監(jiān)聽(tīng)該事件作出要繪制哪 個(gè)類型的Shape的行為,但是這種方式使Shape和控件系統(tǒng)緊密耦合。我們換種思路。 我們會(huì)發(fā)現(xiàn)當(dāng)選中某一個(gè)按鈕時(shí),每個(gè)按鈕所做的事情不一樣,也就是說(shuō)圖形編輯器的狀態(tài)會(huì)影響程序要執(zhí)行的 動(dòng)作。這種情況特別適合使用狀態(tài)模式進(jìn)行設(shè)計(jì)。因此我們引進(jìn)一個(gè)中間層,讓IconButton的狀態(tài)切換與狀態(tài)機(jī) 進(jìn)行交互。使用狀態(tài)模式我們能夠顯著的消除掉if/el

5、se或switch/case語(yǔ)句的使用。 上述分析后,我們會(huì)發(fā)現(xiàn),每一個(gè)IconButton對(duì)應(yīng)一個(gè)狀態(tài),例如RectButton選中時(shí),對(duì)應(yīng)的是CRectState。 CircleButton選中時(shí),切換到CCircleState。因此我們只要監(jiān)聽(tīng)I(yíng)conButton的Selected事件,在事件響應(yīng)函數(shù) 中進(jìn)行狀態(tài)的切換。那么由誰(shuí)來(lái)進(jìn)行狀態(tài)切換呢? 狀態(tài)設(shè)計(jì)模式涉及到兩個(gè)層次,第一層次是CStateManager類負(fù)責(zé)所有狀態(tài)管理,其持有一個(gè)CurrentState的指 針,用于指向當(dāng)前的狀態(tài)。當(dāng)CStateManager設(shè)置狀態(tài)時(shí),最好能夠發(fā)送狀態(tài)發(fā)生改變的消息,并且 CurrentSt

6、ate針指向剛設(shè)置的狀態(tài)。因此由CStateManager來(lái)進(jìn)行狀態(tài)切換是非常合適的。 第二節(jié):UIPPaint需求分析-狀態(tài)模式6 第二個(gè)層次是CStateBase以及所有的子類。 第二節(jié):UIPPaint需求分析-狀態(tài)模式7 那么StateBase需要哪些操作呢? 根據(jù)需求:我們會(huì)發(fā)現(xiàn)當(dāng)處于CRectState時(shí)候,鼠標(biāo)點(diǎn)擊PaintArea時(shí),需要?jiǎng)?chuàng)建一個(gè)以鼠標(biāo)點(diǎn)擊處為中心點(diǎn)的 Rect形狀。而其他例如處于CCircleState,CTriangleState狀態(tài)時(shí),表現(xiàn)形式與CRectState相同,唯一 區(qū)別就是產(chǎn)生的形狀不同而已。 當(dāng)處于CFillState時(shí),點(diǎn)擊PaintAre

7、a控件中任意存在的形狀,都會(huì)填充點(diǎn)中的圖形。 因此我們會(huì)發(fā)現(xiàn)都是PaintArea鼠標(biāo)點(diǎn)擊有關(guān),因此最起碼StateBase中需要一個(gè)虛函數(shù)例如: virtual void MouseDown(const Point& pt)的函數(shù)。 為了更加靈活的處理切換狀態(tài),例如有一種需求,假設(shè)當(dāng)我們選中繪制圖像狀態(tài)時(shí)使用正常的鼠標(biāo)指 針,而在選中CFillState時(shí),要使用一個(gè)油漆桶鼠標(biāo)指針,這時(shí)候就需要我們能夠響應(yīng)狀態(tài)切換的消息。 因此再增加兩個(gè)狀態(tài)切換的虛函數(shù): virtual void OnEnter() /進(jìn)入當(dāng)前狀態(tài)我們應(yīng)該要做什么事情呢? virtual void OnLeave(

8、) /離開(kāi)當(dāng)前狀態(tài)我們應(yīng)該要做什么事情呢? 第三節(jié):UIPPaint需求分析-命令模式8根據(jù)需求: 我們會(huì)發(fā)現(xiàn)當(dāng)處于CRectState時(shí)候,鼠標(biāo)點(diǎn)擊PaintArea時(shí),需要?jiǎng)?chuàng)建一個(gè)以鼠標(biāo)點(diǎn)擊處為中心點(diǎn)的形狀。 并且支持形狀的創(chuàng)建和撤銷操作,意味著我們支持形狀創(chuàng)建的Undo/Redo功能。 我們定義ICommand接口用于支持Undo/Redo功能。該接口具有Execute()接口函數(shù)支持Redo操作,Undo()接口函 數(shù)用于支持Undo功能。 CShapeCreateCommand實(shí)現(xiàn)了ICommand接口,用于支持形狀的創(chuàng)建和撤銷。該命令是在: StateBase:MouseDown時(shí)

9、被添加到CUndoManager中進(jìn)行管理的。 CUndoManager類用于管理所有的命令對(duì)象,需要支持三個(gè)功能: 1、 命令的添加 2、 Undo棧和Redo棧的交互 3、 記錄從當(dāng)前開(kāi)始往前N個(gè)命令(N代表最多可以Undo/Redo多少步) 第四節(jié):UIPPaint需求分析-訪問(wèn)者模式9根據(jù)需求: 我們會(huì)發(fā)現(xiàn)當(dāng)處于CRectState時(shí)候,鼠標(biāo)點(diǎn)擊PaintArea時(shí),需要?jiǎng)?chuàng)建一個(gè)以鼠標(biāo)點(diǎn)擊處為中心點(diǎn)的形狀。 因此我們需要形狀(或者叫圖元) 目前支持三種圖元 : CRectShape,CCircleShape,CTriangleShape,他們都繼承自CShapeBase類,每種圖元都能

10、 被點(diǎn)中并且被填充,因此需要支持鼠標(biāo)碰檢事件。 所有的圖元我們需要使用CShapManager來(lái)進(jìn)行管理。 第四節(jié):UIPPaint需求分析-訪問(wèn)者模式10 圖元的繪制有兩種方式: 1、在每個(gè)CShapeBase中定義一個(gè)虛函數(shù)Render(),每個(gè)子類都o(jì)verride Render函數(shù),實(shí)現(xiàn)繪制代碼,這意味著 所有的繪制代碼都分散在每個(gè)實(shí)際的子類中。 2、 我們使用訪問(wèn)者模式,所有的實(shí)際子類的繪制代碼全部放在CDrawerVisitor類中,如果要修改或增加功能,只要 修改CDrawerVisitor類就可以了。我們使用該方式實(shí)現(xiàn)圖元的渲染。 CShapeBase中有一個(gè)純虛函數(shù): 第五節(jié)

11、:UIPPaint需求分析-中間者模式11 前面已經(jīng)將涉及到應(yīng)用程序交互的類都定義出來(lái)了,那么他們之間如何協(xié)作呢? 比較清晰的方式是劃分模塊: UIPaint模塊-中間者類-UIPLib模塊。 中間者類知道所有的UIPaint模塊的對(duì)象,而UIPaint模塊的對(duì)象,例如每一個(gè)StateBase的子類都能夠查找到中間者類。 中間者類監(jiān)聽(tīng)UIPLib中的控件的所有輸入事件,例如監(jiān)聽(tīng)CIconButton的Select事件,根據(jù)哪個(gè)CIconButton被選中, 作出響應(yīng)的狀態(tài)切換(調(diào)用中間者類所擁有的StateManager,然后調(diào)用StateManager的SetCurrentState函數(shù)使?fàn)?/p>

12、態(tài) 發(fā)生切換) 所有的輸出也通過(guò)中間者類進(jìn)行,監(jiān)聽(tīng)CPaintArea類的RenderEvent,將所有UIPPaint中的圖元渲染到CPaintArea控 件上。 第五節(jié):UIPPaint需求分析-中間者模式12 第五節(jié):UIPPaint需求分析-中間者模式13 1、CIconButton Select事件處理時(shí)序圖: 第五節(jié):UIPPaint需求分析-中間者模式14 2、CPaintArea MouseButtonEvent事件處理時(shí)序圖: 第六節(jié):UIPPaint需求分析-門(mén)面模式15 需求分析: 我們會(huì)發(fā)現(xiàn)中間者M(jìn)ediator作為中心的周轉(zhuǎn)站,其他的協(xié)作類都是通過(guò)中間者進(jìn)行通信,因此

13、中間者模式是一種行為模式。 中間者中引用了所有協(xié)作類,或者子模塊(UndoRedo模塊,狀態(tài)機(jī)模塊,輸入輸出模塊,圖元顯示模塊),因此導(dǎo)致子模塊眾多。使用者需要了解各個(gè)模塊之間的協(xié)作關(guān)系。 我們讓中間者又充當(dāng)門(mén)面的角色(CFacadeMediator),讓一系列復(fù)雜的類包裝成一個(gè)簡(jiǎn)單的封閉接口。 這意味著所有的重要功能都通過(guò)CFacadeMediator類來(lái)進(jìn)行操作,不要使用子模塊的接口函數(shù),而是將子模塊的接口函數(shù)都封裝在CFacadeMediator類中,這樣即使再多再?gòu)?fù)雜的子模塊,我們都把他們隱藏起來(lái),你不需要調(diào)用子模塊的相關(guān)函數(shù),而是調(diào)用CFacadeMediator中的封裝的相關(guān)接口函

14、數(shù)。這樣就避免了過(guò)多類協(xié)作,使用起來(lái)很復(fù)雜的狀況。 由此可見(jiàn),門(mén)面模式是一種結(jié)構(gòu)模式,將系統(tǒng)中的復(fù)雜的類協(xié)作關(guān)系扁平化。 第六節(jié):UIPPaint需求分析-門(mén)面模式16 第七節(jié):UIPPaint需求分析-職責(zé)鏈模式17 需求分析: 當(dāng)我們按下F1鍵時(shí),當(dāng)前獲得焦點(diǎn)的控件會(huì)接受到F1鍵盤(pán)事件,彈出一個(gè)MsgBox對(duì)話框,顯示當(dāng)前控件的用途幫助信息。 最簡(jiǎn)單的方法是監(jiān)聽(tīng)每個(gè)控件的F1鍵盤(pán)事件,作出響應(yīng)。但是代碼分散到了各個(gè)控件的事件響應(yīng)實(shí)現(xiàn)中。而且如果我們要調(diào)整某些控件不提供幫助,而有些提供,意味著幫助系統(tǒng)是可配置的。在這種情況下,我們需要更靈活的機(jī)制。而職責(zé)鏈特別適合這種情形。CControlHelpChain代表一個(gè)職責(zé)鏈,通過(guò)next指針形成鏈表。每一個(gè)CControl HelpChain有一個(gè)指針指向CControlBase。CControlHelpChain有一個(gè)靜態(tài)的成員函數(shù)用于監(jiān)聽(tīng)CControlBase的F1鍵盤(pán)事件,在CControlHelpChain的構(gòu)造函數(shù)中,將該靜態(tài)成員監(jiān)聽(tīng)函數(shù)注冊(cè)到其所指向的CControlBase中。 使用靜態(tài)成員函數(shù),減少內(nèi)存使用,更能聽(tīng)體現(xiàn)我們UIPLib的事件系統(tǒng)的實(shí)用性以及強(qiáng)大功能。 控件幫助系統(tǒng)職責(zé)鏈?zhǔn)腔诳丶?,因此不需要與中

溫馨提示

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

評(píng)論

0/150

提交評(píng)論