版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
本文提出了一種界面設(shè)計(jì)中的架構(gòu)模式一界面組裝器模式,它致力于分解界面,將界面和組裝行為解耦,將界面邏輯處理與領(lǐng)域邏輯處理解耦,這樣我們?cè)陂_發(fā)GUI胖客戶端界面應(yīng)用時(shí)可以從眾多的界面控制管理中解脫出來,而專注于我們的后臺(tái)業(yè)務(wù)邏輯的開發(fā)。通過該模式,我們可以動(dòng)態(tài)地組裝我們的界面,我們甚全還可以在我們的界面中輕松地插入transaction事務(wù)或session會(huì)話管理。本文將通過分析設(shè)計(jì)一個(gè)架構(gòu)的過程來講解該模式,從一個(gè)簡(jiǎn)單的設(shè)計(jì)模型開始,一步步走向一個(gè)完整的架構(gòu)。借此也向大家展示一個(gè)架構(gòu)設(shè)計(jì)的思維歷程。另外,本文給出了EclipseSWT(StandardWidgetToolkit)的示例。問題引出界面設(shè)計(jì)常常是模式產(chǎn)生的根源,無論是架構(gòu)模式,還是設(shè)計(jì)模式,比如MVC模式,Observer,F(xiàn)acade等,也是整個(gè)軟件行業(yè)向前發(fā)展的動(dòng)力。遺憾的是,即使在軟件技術(shù)發(fā)達(dá)的今天,界面設(shè)計(jì)仍是軟件設(shè)計(jì)中的難以突破的瓶頸之一。我們用過Javaswing或EclipseSWT作過項(xiàng)目的都知道,要將界面進(jìn)行分解是很困難的,它不像我們的業(yè)務(wù)邏輯,可以方便地按職責(zé)分解到不同的類中去實(shí)現(xiàn),因?yàn)楦鱾€(gè)業(yè)務(wù)邏輯之間耦合度很低。但界面邏輯不一樣,你不可能將一個(gè)文本框的讀取操作委任到另一個(gè)類中去,而且各個(gè)界面元素之間相互依賴,無法去除耦合,一般的做法只能是在界面元素的事件觸發(fā)(比如按鈕點(diǎn)擊事件)時(shí),將輸入數(shù)據(jù)封裝成一個(gè)數(shù)據(jù)對(duì)象傳給后臺(tái)的邏輯處理類來處理。Eclipse的Wizard框架在界面分解上提供了一種很好的實(shí)踐,它可以將按鈕區(qū)和其他界面區(qū)分離出來,用類似MVC的方式實(shí)現(xiàn)了Wizard框架。但這個(gè)實(shí)現(xiàn)并非沒有瑕疵,一個(gè)缺點(diǎn)是wizard是一個(gè)plug-in,這樣的話就減少了可重用性,不能移植到eclipse以外的環(huán)境。另一個(gè)缺點(diǎn)就是它引入了很大的復(fù)雜性,而且在一些對(duì)界面元素的控制上喪失了一些精細(xì)控制的能力,這可能是它過度地強(qiáng)調(diào)了自動(dòng)化和用戶擴(kuò)展的方便性的緣故。比如,用戶不能將自己的邏輯插入按鈕區(qū)的按鈕事件控制中,而只能在自定義區(qū)的界面元素Listener中設(shè)定按鈕區(qū)狀態(tài),如果用戶自定義的界面元素很多,就需要很多個(gè)Listener來組合判斷一個(gè)按鈕狀態(tài)(如是否進(jìn)行“下一步”),這樣的話就很影響性能,而且無端地多了一堆復(fù)雜的邏輯判斷,也就是說本來只需在按鈕Listener事件中處理的邏輯現(xiàn)在要分散在各個(gè)界面元素的Listener中去處理。這也正是設(shè)計(jì)上一個(gè)值得反復(fù)強(qiáng)調(diào)的普遍問題:當(dāng)你要保持架構(gòu)或設(shè)計(jì)的完美性時(shí)必然會(huì)以喪失其他特性為代價(jià)。世上永遠(yuǎn)沒有完美的東西,我們只關(guān)注適合我們的。我下面要提出的這個(gè)架構(gòu)模式的靈感來自于我的一個(gè)真實(shí)項(xiàng)目,一個(gè)用RSA(RationalSoftwareArchitect)/Eclipse建模的項(xiàng)目,在RSA環(huán)境中,讀寫模型都必須在一個(gè)特有的context下才能操作,這就意味著我在界面的啟動(dòng)之前必須封裝好輸入數(shù)據(jù),關(guān)閉之后返回輸出數(shù)據(jù),而不是直接處理數(shù)據(jù),必須對(duì)輸入/輸出數(shù)據(jù)對(duì)象進(jìn)行封裝。正如前面提到的,這種情況界面設(shè)計(jì)中很普遍。所以,在模式命名時(shí)我用了組裝器-assembler這個(gè)詞,有一層意思是輸入/輸出數(shù)據(jù)對(duì)象的組裝,另一層意思就是界面部件(界面元素的集合)的組裝,這里的組裝還有更深層次的涵義就是指界面部件的可裝配性,可以在運(yùn)行時(shí)動(dòng)態(tài)組裝。而且這個(gè)模式可以用任何語(yǔ)言(Java,C++等)來實(shí)現(xiàn)。在這里我會(huì)從一個(gè)簡(jiǎn)單的設(shè)計(jì)模型開始,一步步走向一個(gè)完整的架構(gòu)。借此也向大家展示一個(gè)架構(gòu)設(shè)計(jì)的思維歷程。本文中給出了EclipseSWT(StandardWidgetToolkit)的示例。界面分解在EclipseSWT中,有幾個(gè)重要的界面部件,一個(gè)是Shell-界面的最外層容器,類似JavaSwing中的Frame,另一個(gè)就是Composite-界面元素的集合的容器,類似JavaSwing中的Panel。我們的界面分解將從Composite開始,(Shell本身是不需要分解的)。我們可以在Shell中裝配上一個(gè)空的Composite,然后我們的具體界面元素都定義在這個(gè)Composite里。這樣就把Composite邏輯從Shell中分離出來了,因此我們現(xiàn)在有了2個(gè)類(目前我們用概念類來表示):圖1.把Composite邏輯從Shell中分離出來Editor:該類處理Shell的邏輯,如顯示-show,關(guān)閉-close,它負(fù)責(zé)創(chuàng)建和銷毀EditorComposite。EditorComposite:該類處理Composite的界面邏輯,如創(chuàng)建界面元素。有兩點(diǎn)值得注意,第一,Editor負(fù)責(zé)EditorComposite的創(chuàng)建和銷毀,也就是生命周期的管理。那么我們可以想到,如果我們的界面需要transaction-事務(wù)或session-會(huì)話的管理,那么我們完全可以讓Editor來負(fù)責(zé)這項(xiàng)職責(zé),而不是分散在各個(gè)EditorComposite中。怎么擴(kuò)展界面的事務(wù)功能可能會(huì)很復(fù)雜,這已經(jīng)超出本文的討論范圍,我只是從架構(gòu)的層面來分析可能有的可擴(kuò)展性。第二,一個(gè)Editor可以包括多個(gè)EditorComposite,比如我們的屬性頁(yè),此時(shí)我們?cè)赟hell中定義的空的Composite將會(huì)是一個(gè)TabFolder.還有一種情況,就是我們可以根據(jù)某種邏輯來判斷我們需要裝配哪個(gè)EditorComposite。這就要求我們有一個(gè)裝配的行為。界面部件裝配當(dāng)我們的裝配邏輯很簡(jiǎn)單時(shí),我們可以定義一個(gè)assemble()方法來負(fù)責(zé)裝配行為。但是當(dāng)我們的界面需要組裝一系列EditorComposite時(shí),就會(huì)牽涉到選擇邏輯,選擇邏輯不一定很復(fù)雜,但我們還是應(yīng)該把這種行為從Editor中分離出來,這樣Editor可以集中精力負(fù)責(zé)與用戶交互方面的職責(zé),而裝配行為被分配到一個(gè)新的類EditorAssembler中,這樣做還有一個(gè)好處,就是我們一旦有新的EditorComposite需要添加時(shí),我們只需要改變EditorAssembler的代碼,而不用修改Editor的代碼,這就把變化隔離出來,對(duì)Editor的修改關(guān)閉,對(duì)裝配行為的擴(kuò)展開放。這正是面向?qū)ο笤O(shè)計(jì)領(lǐng)域反復(fù)強(qiáng)調(diào)的基本原則-開放-封閉原則(Open-ClosePrinciple)o經(jīng)過重構(gòu)后的架構(gòu)如下圖:圖2.重構(gòu)后的架構(gòu)EditorAssembler:該類處理EditorComposite的創(chuàng)建,還包括多個(gè)EditorComposite的選擇邏輯。這里的選擇邏輯我們可以用if/else或switch/case來硬編碼,如果邏輯不是很復(fù)雜而且今后的修改不會(huì)太頻繁的話,用這種方法就足夠了,當(dāng)然可以考慮將多個(gè)EditorComposite的裝載信息專門用一個(gè)資源/信息類來存儲(chǔ),這在EditorComposite比較多的情況下很有效,這樣每次添加EditorComposite就只需要改變這個(gè)資源類,這是一個(gè)很有用的建模原則(為了簡(jiǎn)化我們的核心模型,我在這里不將這個(gè)資源類表示出來)。如果進(jìn)一步考慮到我們的組裝邏輯會(huì)比較復(fù)雜,或會(huì)比較容易改變,甚至在運(yùn)行時(shí)動(dòng)態(tài)改變,我們就可以將眾多的EditorComposite和復(fù)雜的邏輯存儲(chǔ)在一個(gè)元數(shù)據(jù)文件中,如XML或配置文件。這樣,有新的EditorComposite需要支持,或修改裝配邏輯時(shí),不用修改EditorAssembler類,只要修改元數(shù)據(jù)文件即可。這樣就可以很動(dòng)態(tài)的配置我們的界面。這里會(huì)有一個(gè)架構(gòu)權(quán)衡的問題,元數(shù)據(jù)由它的優(yōu)點(diǎn),也有它的缺點(diǎn),其一,必須編寫解析它的類,復(fù)雜性增加了,其二,不需要編譯是它的優(yōu)點(diǎn)也是它的缺點(diǎn),對(duì)XML或配置文件我們可以隨意修改,只有在運(yùn)行時(shí)發(fā)現(xiàn)異常才知道改錯(cuò)了,而且也可能被人蓄意破壞掉。所以我們只在真的需要很頻繁地修改EditorComposite的配置或經(jīng)常需要增加EditorComposite時(shí)才采用元數(shù)據(jù)方案。在這里我傾向于采用資源類方案。IO數(shù)據(jù)裝配模型設(shè)計(jì)進(jìn)行到這里,我們似乎缺少了對(duì)數(shù)據(jù)流的建模,在一個(gè)標(biāo)準(zhǔn)的界面程序中,我們首先會(huì)有一組輸出數(shù)據(jù),比如按”O(jiān)K”按鈕之后,我們需要將界面元素上的輸入信息輸出到后臺(tái)邏輯類來處理或直接調(diào)用好幾個(gè)邏輯類分別處理不同的界面元素輸入信息了。我們一般習(xí)慣上可能直接將這個(gè)數(shù)據(jù)傳遞到邏輯類來處理。這樣做三個(gè)缺點(diǎn):其一,如果我們的數(shù)據(jù)讀寫處理要求必須在特定的context中才能進(jìn)行,這樣的話我們不能在界面中直接調(diào)用后臺(tái)邏輯處理類了。其實(shí)這種限制并不罕見,在一些涉及底層(比如協(xié)議層)的開發(fā)時(shí),經(jīng)常會(huì)碰到只能讀不能寫的情況。其二,UI的可替代性差,假如我們今后需要一種方案可以在運(yùn)行時(shí)可以替換不同的UI但輸出的數(shù)據(jù)是一樣的,也就是說后臺(tái)邏輯處理完全一致,那么這種情況我們就需要每一個(gè)UI自己去調(diào)用后臺(tái)邏輯類,重復(fù)編碼,而且可能由于程序員的失誤每一個(gè)UI用了一個(gè)邏輯類,從而導(dǎo)致一個(gè)完全相同行為的類有了好幾個(gè)不一致實(shí)現(xiàn)版本,這樣不僅嚴(yán)重違反了面向?qū)ο笤O(shè)計(jì),而且還可能產(chǎn)生難以預(yù)料的bug,難以維護(hù)。其三,UI的可重用性差,對(duì)于上面多個(gè)UI對(duì)應(yīng)一種邏輯處理的例子,由于UI依賴了后臺(tái)邏輯類,如果今后要修改邏輯類結(jié)構(gòu)的話,我們就需要修改每一個(gè)UI。如果我們還有一種需求是要支持一個(gè)UI在不同的環(huán)境下需要不同的后臺(tái)邏輯類時(shí),我們可能要專門在一個(gè)UI中設(shè)置一個(gè)屬性來標(biāo)識(shí)后臺(tái)將要使用的邏輯類。這會(huì)很復(fù)雜。解決上面幾個(gè)缺點(diǎn)只有一種方法,就是將后臺(tái)邏輯類與UI解耦。如果我們把要處理的輸出數(shù)據(jù)打包成一個(gè)輸出數(shù)據(jù)對(duì)象從界面統(tǒng)一輸出,再由UI的調(diào)用者決定調(diào)用哪一個(gè)后臺(tái)邏輯類來處理數(shù)據(jù),而不是UI自己決定調(diào)用行為。還有一個(gè)輸入數(shù)據(jù)對(duì)象就很好理解了,我們調(diào)用UI時(shí),可能某些界面元素需要的從環(huán)境中動(dòng)態(tài)裝載數(shù)據(jù),比如一個(gè)下列列表,還有一些我們上一次配置好的數(shù)據(jù)這次需要更新,也需要將已有數(shù)據(jù)導(dǎo)入。所以我們需要一個(gè)輸入數(shù)據(jù)對(duì)象。這就得到下面的模型:圖3.輸入數(shù)據(jù)對(duì)象OEditorConipositeOEditorConipositeInputDataObject:該類封裝了輸入數(shù)據(jù)。由EditorComposite負(fù)責(zé)解析這些數(shù)據(jù)。OutputDataObject:該類封裝了輸出數(shù)據(jù)。由EditorComposite負(fù)責(zé)產(chǎn)生這些數(shù)據(jù)。Editor負(fù)責(zé)傳輸這兩個(gè)數(shù)據(jù)對(duì)象。重構(gòu)架構(gòu)從上面的模型我們可以看出Editor類其實(shí)相當(dāng)于一個(gè)Facade,所有的界面與用戶的交互都由它負(fù)責(zé)集中調(diào)度管理,Editor會(huì)將裝配行為分配給EditorAssembler類來處理,它還負(fù)責(zé)臨時(shí)存儲(chǔ)輸入輸出數(shù)據(jù),當(dāng)然如果我們有類似transaction或session之類的處理會(huì)由Editor委派到別的相關(guān)類去處理。應(yīng)用Facade設(shè)計(jì)模式,我們可以給Editor改個(gè)名字叫EditorFacade,這樣更能體現(xiàn)設(shè)計(jì)者的意圖,千萬(wàn)不要忽視類的命名,設(shè)計(jì)是一門嚴(yán)肅的科學(xué),每一個(gè)細(xì)節(jié)我們都不能茍且,對(duì)架構(gòu)的設(shè)計(jì)更要嚴(yán)謹(jǐn)。命名可以起到溝通的作用,還能起到提醒的功能,EditorFacade提醒我們以后要給它添加新的行為是記住它是一個(gè)Facade,不能將不相干的職責(zé)分配進(jìn)來。另外,我發(fā)現(xiàn)添加了InputDataObject類后,EditorComposite就有兩個(gè)職責(zé):裝載界面元素初始化數(shù)據(jù)(一些需要從環(huán)境中動(dòng)態(tài)獲得的輸入數(shù)據(jù),從InputDataObject對(duì)象中獲得)和顯示上一次編輯的數(shù)據(jù)(也從InputDataObject對(duì)象中獲得),我們定義兩個(gè)方法來分別處理:loadDataInfo()-裝載初始化數(shù)據(jù);showPreInfo()-顯示上一次編輯的數(shù)據(jù)。當(dāng)然,一般來說這兩個(gè)方法是私有的-private,因?yàn)檫@是EditorComposite自身的內(nèi)部邏輯,但我們?cè)谶@個(gè)架構(gòu)中讓它成為公有的-public,是因?yàn)槲覀兛梢栽贓ditorAssembler類中集中控制它的調(diào)用,而且每一個(gè)EditorComposite都會(huì)有裝載初始化數(shù)據(jù)和顯示已有數(shù)據(jù)的行為,那么為什么不抽象出來呢,以便讓EditorComposite的開發(fā)提供者更清楚自己的職責(zé),雖然這么做有點(diǎn)破壞EditorComposite的封裝性和其中方法的私密性,但從架構(gòu)的角度來講這種破壞是合適的,值得的。再看看前面的EditorAssembler類,它其實(shí)有兩個(gè)職責(zé),一個(gè)是創(chuàng)建EditorComposite,還有一個(gè)就是從幾個(gè)EditorComposite選擇出一個(gè)的判斷邏輯。如果我們把這兩個(gè)不相干的職責(zé)解耦,應(yīng)用Factory設(shè)計(jì)模式,就可以將創(chuàng)建EditorComposite的工作委任給一個(gè)EditorCompositeFactory的新類。經(jīng)過以上幾項(xiàng)重構(gòu)后得到以下概念類模型:圖4.概念類模型實(shí)現(xiàn)架構(gòu)經(jīng)過上面的分析建模,我們可以開始實(shí)現(xiàn)架構(gòu)了,從上面的概念模型我們可以很容易地抽象出相應(yīng)的接口來。首先,我們看看EditorFacade類,基于我們上面的討論,不同的界面可能有不同的需求,比如有的要支持transaction-事務(wù),那么EditorFacade的實(shí)現(xiàn)就會(huì)不同,所以我們有必要提取出一個(gè)接口來表示,下面列出了這個(gè)接口IEditorFacade:清單1:IEditorFacade.javapublicinterfaceIEditorFacade(publicvoidshow();publicIlnputDataObjectgetInputData();publicvoidsetInputData(IInputDataObjectinputData);publicIOutputDataObjectgetOutputData();publicvoidsetOutputData(IOutputDataObjectoutputData);publicbooleanisFinishedOK();publicCompositegetRootComposite();publicvoidsetAssembler(IEditorAssemblerassembler);publicvoidclose(booleanstatus);}那么EditorFacade類的部分代碼如下:清單2:EditorFacade.javapublicclassEditorFacadeimplementsIEditorFacade(privateShellshell;//validateifeditorisclosedwithOKorCancelprivatebooleanfinishedOK;//inputdataprivateIInputDataObjectinputData;//outputdataprivateIOutputDataObjectoutputData;privateCompositecomposite;privateIEditorAssemblerassembler;privatevoidcreateSShell()(shell=newShell();shell.setLayout(newGridLayout());createComponent();}privatevoidcreateComponent()(composite=newComposite(shell,SWT.NONE); assembler.create(this);}publicvoidshow()(this.shell.open();assembler.showPreInfo();}publicEditorFacade(IEditorAssemblerassembler,IlnputDataObjectinputData)(this.assembler=assembler;this.inputData=inputData;this.createSShell();}publicCompositegetRootComposite()(returncomposite;}publicvoidclose(booleanstatus)(finishedOK=status;this.shell.close();}}下一步,我們將兩個(gè)IO數(shù)據(jù)類定義出來,很顯然,不同的界面會(huì)有不同的輸入輸出數(shù)據(jù),在這里我們只能定義出兩個(gè)抽象的接口IInputDataObject和IOutputDataObject,它們繼承了序列化java.io.Serializable接口,里面并無其它內(nèi)容。這里注意一點(diǎn),空的接口并非無意義,它可以起到標(biāo)識(shí)的作用,另外,它隱藏了具體實(shí)現(xiàn),在傳遞數(shù)據(jù)時(shí)傳遞者不用知道具體數(shù)據(jù)內(nèi)容,這樣傳遞者類具有更好的重用性,而且具體數(shù)據(jù)類也不用暴露給不該知道它的類-傳遞者類,這正是另一個(gè)面向?qū)ο蟮幕驹瓌t-迪米特法則(LoD):不要和陌生人說話。下面給出IInputDataObject的清單:清單3:IInputDataObject.javapublicinterfaceIInputDataObjectextendsSerializable(}接下來,我們看看EditorAssembler類的實(shí)現(xiàn),根據(jù)前面的討論,它封裝了界面的裝配邏輯,一定會(huì)被修改的,那么我們就需要一個(gè)接口IEditorAssembler來規(guī)范它的行為,在這里我還給出了一個(gè)抽象類AbstractEditorAssembler,實(shí)現(xiàn)了裝載單個(gè)EditorComposite的方法,另外我還給出了一個(gè)具體的EditorAssembler類,這是一個(gè)每次只裝載一個(gè)EditorComposite的例子,代碼清單如下:清單4:lEditorAssembler.javapublicinterfacelEditorAssembler(/**createeditorbodyandinit@parameditor*/publicvoidcreate(IEditorFacadeeditor);/**createeditorcomposite@parameditor@paramcompositeClassID:compositeclassname,e.g.test.view.TestComposite@return*/publicIEditorCompositecreateComposite(IEditorFacadeeditor,StringcompositeClassID);/**showexistinfoinUIforupdate.*/publicvoidshowPreInfo();}清單5:AbstractEditorAssembler.javapublicabstractclassAbstractEditorAssemblerimplementsIEditorAssembler(publicIEditorCompositecreateComposite(IEditorFacadeeditor,StringcompositeClassID)(IEditorCompositebody;body=EditorCompositeFactory.createComposite(compositeClassID,editor);body.create(editor.getRootComposite());body.setEditor(editor);returnbody;}清單6:StandaloneEditorAssembler.javapublicclassStandaloneEditorAssemblerextendsAbstractEditorAssembler(privateStringcompositeClassID;privateIEditorCompositebodyComposite;/***@paramcompositeClassID:compositeclassqulifiedname,.ibm..XXComposite;*/publicStandaloneEditorAssembler(StringcompositeClassID)(positeClassID=compositeClassID;}publicvoidcreate(IEditorFacadeeditor)(bodyComposite=createComposite(editor,compositeClassID);if(bodyComposite!=null)bodyComposite.loadDataInfo();}publicvoidshowPreInfo()(bodyComposite.showPreInfo();}}接下來,是EditorCompositeFactory的實(shí)現(xiàn),這個(gè)類的實(shí)現(xiàn)比較簡(jiǎn)單,只是根據(jù)類名產(chǎn)生類:清單7:EditorCompositeFactory.javapublicclassEditorCompositeFactory(/**createIEditorComposite@paramclsName@parameditor@return*/publicstaticIEditorCompositecreateComposite(StringclsName,lEditorFacadeeditor)(lEditorCompositecomposite=null;try(Classcls=Class.forName(clsName);if(cls!=null)composite=(IEditorComposite)cls.newInstance();}catch(Exceptione)(e.printStackTrace();}if(composite!=null)(composite.setEditor(editor);}returncomposite;}}最后,就是EditorComposite的實(shí)現(xiàn)了,很顯然每個(gè)界面的EditorComposite都不一樣,所以我們?cè)谶@里只定義了一個(gè)接口來規(guī)范一下行為,具體的EditorComposite實(shí)現(xiàn)我會(huì)在代碼附件中的測(cè)試包中給出。清單8:IEditorComposite.javapublicinterfaceIEditorComposite(/**setupcompositeUI*/publicvoidcreate(Compositeparent);/**setthecurrenteditorforshellcloseanddataset*/publicvoidsetEditor(IEditorFacadeeditor);/**showpreviousdatainformationinUI*/publicvoidshowPreInfo();publicvoidloadDataInfo();}下面,我們編寫一些測(cè)試代碼來測(cè)試它,這個(gè)測(cè)試應(yīng)用是要編寫一個(gè)電話簿,為了簡(jiǎn)單起見我只定義了一個(gè)EditorComposite-PhoneBookComposite,在編寫組裝邏輯時(shí)也只是示例性地改變了一下界面的標(biāo)題和尺寸。(詳細(xì)代碼見代碼下載)清單9:PhoneBookEditorAssembler.javapublicvoidcreate(IEditorFacadeeditor)(if(compositeType==0)(//itisaphonebook.bodyComposite=createComposite(editor,"test.PhoneBookComposite");| 10 20 30 40 50 60 70 80 9|| XMLerror:Thepreviouslineislongerthanthemaxof90characters 1editor.getShell().setText(〃PhoneBook");editor.getShell().setSize(400,300);editor.getShell().redraw();if(bodyComposite!=null)bodyComposite.loadDataInfo();}elseif(compositeType==1)(//itisamemobook.bodyComposite=createComposite(editor,"test.PhoneBookComposite");| 10 20 30 40 50 60 70 80 9|| XMLerror:Thepreviouslineislongerthanthemaxof90characters 1editor.getShell().setText("MemoBook");editor.getShell().setSize(500,300);editor.getShell().redraw();if(bodyComposite!=null)bodyComposite.loadDataInfo();}}清單10:Main.javapublicstaticvoidmain(String[]args)(〃定義PhoneBookEditorAssembler。IEditorAssemblerassembler=newPhoneBookEditorAssembler(0);〃定義PhoneBook輸入數(shù)據(jù)IInputDataObjectinputData=newPhoneBookInputDO("LYL",);〃定義PhoneBookeditorEditorFacadeeditor=newEditorFacade(assembler,inputData);editor.show();if(editor.isFinishedOK())(〃取出PhoneBook輸出數(shù)據(jù)。if(editor.getOutputData()instanceofPhoneBookOutputDO)(PhoneBookOutputDOoutputData=(PhoneBookOutputDO)editor.getOutputData();Stringname=outputData.getName();Stringphone=outputData.getPhone();System.out.println(〃name:〃+name+";phone:"+phone);}}}接下來,我們可以看一下架構(gòu)的實(shí)現(xiàn)模型,注意,我在畫下面的UML圖時(shí)采用了分層的方式,所有的接口都會(huì)在上面一層,實(shí)現(xiàn)在下面一層,這種分層畫UML圖的方法有助于我們理清架構(gòu)的思路,也便于與開發(fā)組的其他成員溝通。圖5.架構(gòu)的實(shí)現(xiàn)模型卻I-17突€ ipriSJtftfl普口明tw{)爐shovxfrebifci卻I-17突€ ipriSJtftfl普口明tw{)爐shovxfrebifci(j*creatsCompoErte0?shoM句i血{)加醐Intpi白口9*Offk/bD云加U0E曲"網(wǎng)咻MM心C¥y叱ajpupcoltiMClasslD;Strin。ntodvConipoyb?:lEdborOonipcwsite?(XRM白()&ihcwPEeInfo()J'LKPS'■JjTaQJEd&Mf鹽*&成匾I"邙W?composrtftType:ntnFnulEM垃:DhptltD^I:^Objectrautput&au;[{Xrtpul^ntnQbj^ct=:Lunipuiatu:Guiiiix治im曰濟(jì)5麗山I斜:,?u*■■加占OES5■0Abjrra-ftEdjtoTjflssefTrfjfer MJ戲舊另ahoTT(j■&,一iiIL心;JLl坎G()■#rP-r^dti'c.itn.vt.-i(j?salStputData(;■&阻WA.'l!!!、()奉必tF,56lL:E>r(j4tRM/Tl上向i1■#c.'i-it?■;!虬屆至此,我們完成了界面組裝器的核心架構(gòu)的實(shí)現(xiàn),注意,這只是一種實(shí)現(xiàn),并不是界面組裝模式的全部,作為一種模式,它必須有更廣的外延,下面我們將要探討它的模式本質(zhì)。模式與價(jià)值觀這個(gè)模式是一種架構(gòu)模式,模式的定義有三個(gè)要素:?jiǎn)栴},環(huán)境,解決方案,這在前面我們已經(jīng)詳細(xì)地論述過了,在這里我們討論一下其他的參量。每個(gè)模式都有它自己獨(dú)特的價(jià)值觀,那么界面組裝器模式給我們提供了什么樣的價(jià)值觀呢?首先,它的精髓在于這種分解界面,將界面和組裝行為解耦的設(shè)計(jì)思想,這在擁有多個(gè)界面的應(yīng)用中很有益處,當(dāng)界面多的時(shí)候,如果沒有一個(gè)比較集中的調(diào)度控制方式來對(duì)這些界面進(jìn)行管理,就會(huì)形成界面行為無法規(guī)范,風(fēng)格各異,更難以作transaction事務(wù)或session會(huì)話控制。這在小型應(yīng)用開發(fā)中也許不很明顯,但在一個(gè)大中型應(yīng)用中對(duì)分散的不規(guī)范的界面行為進(jìn)行控制將會(huì)是一場(chǎng)惡夢(mèng),到最后可能整個(gè)開發(fā)組都沉浸于bug的修復(fù)和界面修改中,而無暇顧及領(lǐng)域邏輯代碼的編寫。而通過將界面和組裝行為解耦就可以讓開發(fā)人員集中精力于界面邏輯和領(lǐng)域邏輯的開發(fā),而不用每一個(gè)界面都去編寫管理界面的代碼。其實(shí)這也是模式化的一個(gè)優(yōu)點(diǎn),模式可以優(yōu)化我們的架構(gòu),可以規(guī)范開發(fā)行為,因此也會(huì)節(jié)省開發(fā)成本。其二,它將界面邏輯處理與領(lǐng)域邏輯處理(也就是數(shù)據(jù)邏輯處理)解耦。我們將數(shù)據(jù)輸入輸出從界面模型中抽取出來,沒有與界面耦合在一起,這就獲得巨大的好處,第一,我們可以在界面之外來處理數(shù)據(jù),在我們的領(lǐng)域類中處理這些數(shù)據(jù),也就是說界面只是提供了一個(gè)定義數(shù)據(jù)的載體,而這些數(shù)據(jù)是被領(lǐng)域邏輯類使用的,而我們開發(fā)的主要精力也應(yīng)該放在處理業(yè)務(wù)邏輯的領(lǐng)域類上。第二,現(xiàn)在我們將界面和領(lǐng)域類解耦,這樣我們的界面和領(lǐng)域類都可以獨(dú)立地變化,相互之間沒有任何依賴,這就很方便于我們開發(fā)人員的分工,編寫界面的開發(fā)組不用依賴于編寫后臺(tái)邏輯類的開發(fā)組。第三,在做單元測(cè)試-unittest時(shí),開發(fā)后臺(tái)邏輯類的人員可以單獨(dú)測(cè)試領(lǐng)域類,而開發(fā)界面的人員也可以單獨(dú)測(cè)試界面邏輯。第四,當(dāng)我們有多套界面機(jī)制時(shí),我們的后臺(tái)邏輯類可以很方便地接插上去,比如我們要
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝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ù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度互聯(lián)網(wǎng)金融服務(wù)平臺(tái)合作協(xié)議
- 2025版酒店客房服務(wù)員加班補(bǔ)貼聘用合同范本3篇
- 向開發(fā)商解除房屋買賣合同范本(2篇)
- 二零二五年度房產(chǎn)繼承糾紛調(diào)解及手續(xù)辦理合同3篇
- 2025年度生態(tài)環(huán)保鋁合金門窗設(shè)計(jì)與安裝工程協(xié)議3篇
- 導(dǎo)游服務(wù)技能課件
- 2025版鋼波紋管船舶用鋼波紋管采購(gòu)合同2篇
- 二零二五年度城市地下管線規(guī)劃合同3篇
- 2025年度潲水轉(zhuǎn)化為生物能源項(xiàng)目承包合同2篇
- 2025年人教新起點(diǎn)八年級(jí)生物下冊(cè)月考試卷
- 無錫市區(qū)2024-2025學(xué)年四年級(jí)上學(xué)期數(shù)學(xué)期末試題一(有答案)
- 血液凈化中心院內(nèi)感染控制課件
- 年產(chǎn)1.5萬(wàn)噸長(zhǎng)鏈二元酸工程建設(shè)項(xiàng)目可研報(bào)告
- 《北航空氣動(dòng)力學(xué)》課件
- 紡織廠消防管道安裝協(xié)議
- 【MOOC】思辨式英文寫作-南開大學(xué) 中國(guó)大學(xué)慕課MOOC答案
- 期末測(cè)試卷(試題)-2024-2025學(xué)年五年級(jí)上冊(cè)數(shù)學(xué)北師大版
- 2024年下半年中國(guó)石油大連石化分公司招聘30人易考易錯(cuò)模擬試題(共500題)試卷后附參考答案
- 國(guó)有企業(yè)品牌建設(shè)策略方案
- 家政培訓(xùn)講師課件
- 廣東省深圳市龍華區(qū)2023-2024學(xué)年八年級(jí)下學(xué)期期中數(shù)學(xué)試題
評(píng)論
0/150
提交評(píng)論