MVC 是一個(gè)非常常見的設(shè)計(jì)模式,被廣泛運(yùn)用于各種和用戶交互的軟件中,像 java Swing 類庫(kù)和 SWT、J2EE 中的 JSP、wxWidgets、QT 和 Gnome 等??梢院懿豢鋸埖恼f(shuō),幾乎所有和 UI 有關(guān)的類庫(kù),不論什么語(yǔ)言,什么平臺(tái)都或多或少有 MVC 的影子。但是經(jīng)過這么多年的發(fā)展,MVC 這個(gè)設(shè)計(jì)模式已經(jīng)由最初 smalltalk 中的樣子發(fā)生了很多變化,除了數(shù)目讓人眼花繚亂外,很多 MVC 模型之間已經(jīng)有了很大差異,不同的人說(shuō)起 MVC 時(shí),除了基本原理外,摻雜了很多平臺(tái)或者語(yǔ)言相關(guān)的東西,經(jīng)常會(huì)引起很多誤解。PureMVC 是一個(gè)跨平臺(tái)跨語(yǔ)言的 MVC 通用框架,這個(gè)框架基于 MVC 模式設(shè)計(jì),清晰簡(jiǎn)單,了解這個(gè)框架會(huì)有助于重新認(rèn)識(shí) MVC 設(shè)計(jì)模式本身,或者能夠提供一個(gè)基礎(chǔ)讓大多數(shù)人能夠更清晰的交流基于 MVC 的設(shè)計(jì)方案。
PureMVC 是在基于模型、視圖和控制器 MVC 模式建立的一個(gè)輕量級(jí)的應(yīng)用框架,這是一個(gè)開源框架,它最初是被用于 ActionScript 3 語(yǔ)言使用的 Adobe Flex、Flash 和 AIR 之上,現(xiàn)在已經(jīng)移植到幾乎所有主要的軟件平臺(tái)之上見表 1。
Language | Targets |
---|---|
ActionScript 2 | Flex 1.5, Flash 8, FlashLite |
ActionScript 3 | Flex 2, 3, Flash 9/CS3, AIR. |
C# | .NET 1.0/2.0 Silverlight, Windows Mobile and Pocket PC. |
ColdFusion | ColdFusion 8 |
haXe | JavaScript, Flash 8, Flash 9 and the Neko VM. |
Java | Java Mobile, Standard and Enterprise Editions (ME, SE, EE), JavaFX, Servlets, Applets, and GWT |
JavaScript | Browser neutral |
Objective C | Apple iPhone and Mac |
PHP | PHP 5 |
Python | Python 2.5 for wxPython, Google App Engine, Pyjamas [13] |
Ruby | |
C++ | MSVC 8.0/9.0/10.0, MinGW 3.4.5, GNU G++, Embarcadero C++ 6.21 |
PureMVC 框架有兩個(gè)分支版本:標(biāo)準(zhǔn)和多核。標(biāo)準(zhǔn)版提供了一種簡(jiǎn)單的編碼分離的方法,按照基本的 MVC 概念設(shè)計(jì)而成。多核版本支持模塊化編程,允許多個(gè) PureMVC 應(yīng)用運(yùn)行在一起。本文我們主要介紹標(biāo)準(zhǔn)版的功能和使用。
在 MVC 模式中,應(yīng)用程序被分為低耦合的三層:Model、View 和 Controller。PureMVC 在此基礎(chǔ)上有所擴(kuò)充,通過模塊化設(shè)計(jì),致力于進(jìn)一步降低模塊間耦合性,創(chuàng)建了一個(gè)易于擴(kuò)展限制很小的通用框架,圖一是 PureMVC 的設(shè)計(jì)圖。
(查看圖 1 的 清晰版本。)
在 PureMVC 實(shí)現(xiàn)的經(jīng)典 MVC 元設(shè)計(jì)模式中,Model、View 和 Controller 分別由一個(gè)單例類來(lái)管理,合稱為核心層或核心角色。 另外,在 PureMVC 中還提供了一個(gè)單例類 —— Fa?ade,主要作用是作為與核心層通信的唯一接口,簡(jiǎn)化開發(fā)復(fù)雜度。
從上圖中可以看出,除了這幾個(gè)主要對(duì)象以外,框架還有如下類 Proxy、Mediator 和 Command,以下簡(jiǎn)單介紹一下他們的作用。
除了基本的對(duì)象結(jié)構(gòu)以外,為了解耦合,PureMVC 框架中引入了事件機(jī)制,這是個(gè)非常簡(jiǎn)單觀察者設(shè)計(jì)模式,所有的事件都是一個(gè) Notification,不同對(duì)象之間通過 Notification 來(lái)同步操作和交換信息。例如如果想更新界面中某個(gè) Mediator,首先我們定義 Notification 用于此目的,然后注冊(cè) Mediator 監(jiān)聽該 Notification,然后就可以在程序中任何地方生成一個(gè) Notification,通過事件機(jī)制,Mediator 就會(huì)接收到 Notification,然后更新需要的部分。整個(gè)過程 Mediator 只和 Notification 有關(guān),沒有其他依賴,有效的降低了對(duì)象之間的依賴程度。
介紹完 PureMVC 的基本結(jié)構(gòu)和事件模型,我們來(lái)看看一個(gè)典型的 PureMVC 應(yīng)用如何構(gòu)造。首先實(shí)際的應(yīng)用程序都有一個(gè) Fa?ade 子類,這個(gè) Fa?ade 類對(duì)象負(fù)責(zé)初始化 Controller(控制器),建立 Command 與 Notification 名之間的映射,并執(zhí)行一個(gè) Command 注冊(cè)所有的 Model 和 View,一旦初始化的工作做完,對(duì)象之間的關(guān)系建立好以后,應(yīng)用程序就可以正常運(yùn)行了。
PureMVC Java 版本的基本結(jié)構(gòu)
首先我們看看 PureMVC Java 標(biāo)準(zhǔn)的核心類圖,如圖 2 所示:
核心類的實(shí)現(xiàn)完全體現(xiàn)了框架的設(shè)計(jì)意圖,由 IController、IView 和 IModel 三個(gè)接口來(lái)規(guī)范 MVC 三種角色的行為,同時(shí)又提供了三個(gè)默認(rèn)的實(shí)現(xiàn)類。
然后我們?cè)诳纯摧o助性類的類圖:
(查看圖 3 的 清晰版本。)
從中可以看出 IFa?ade 是整個(gè)程序的入口和負(fù)責(zé)管理所有對(duì)象的類,其中可以注冊(cè) proxy、command 和 Mediator,通過 IFa?ade 的子類,系統(tǒng)的各種資源得到統(tǒng)一管理和調(diào)度。
然后可以看到 INotification 是整個(gè)事件驅(qū)動(dòng)模型的核心類,通過事件模型,整個(gè)應(yīng)用程序的各個(gè)部分的耦合度變得非常低,同時(shí)用戶可以自定義 INotification 的子類,從而實(shí)現(xiàn)最大的可定制性。
下面我們用 PureMVC 來(lái)實(shí)現(xiàn)一個(gè)典型的應(yīng)用程序通訊錄,這個(gè)程序因?yàn)橹皇鞘痉叮灾粚?shí)現(xiàn)了基本的編輯和管理功能,下圖是程序運(yùn)行時(shí)的截圖。
當(dāng)用戶填寫正確的用戶名和密碼的時(shí)候,就顯示登陸成功的消息:
當(dāng)用戶填寫錯(cuò)誤的用戶名和密碼的時(shí)候,就顯示登陸不成功的消息:
首先,我們來(lái)看看程序的入口代碼,即 main 函數(shù)所在的類 LoginFacade,這個(gè)類是 Fa?ade 的子類,同時(shí)繼承了 IFacade 接口。
|
LoginFacade 覆蓋父類的三個(gè)初始化方法:initializeController、initializeModel 和 initializeView,作為單例,通過父類的構(gòu)造函數(shù)分別調(diào)用了這三個(gè)函數(shù),從而完成初始化工作。三個(gè)函數(shù)也很簡(jiǎn)單,只是在 initializeController 中注冊(cè)所有的 Command 類,在 initializeModel 中注冊(cè)所有的 Proxy 類,在 initializeView 中注冊(cè)所有 Mediator 類。
Main 函數(shù)很簡(jiǎn)單只是發(fā)送了一個(gè) STARTUP 的消息,該消息會(huì)被 StartupCommand 類接受,從而執(zhí)行相應(yīng)的初始化動(dòng)作。
然后,我們來(lái)看 StartupCommand 類,這個(gè)類很簡(jiǎn)單,在 StartupCommand 中只是設(shè)置了 lookandfeel,然后就調(diào)用系統(tǒng)中已經(jīng)注冊(cè)了的 LoginScreenMediator 類的對(duì)象,然后讓其顯示在桌面上,限于 Swing 的 EDT 特性,所有這些工作都放在 SwingUtilities.invokeLater 中執(zhí)行。
本例中 StartupCommand 沒有執(zhí)行太復(fù)雜的工作,但是實(shí)際運(yùn)行的系統(tǒng),就可以根據(jù)需要在 StartupCommand 中各種需要執(zhí)行的初始化工作。
|
下面我們接著看 LoginScreenMediator 類。
|
一般來(lái)說(shuō),Mediator 這個(gè)類負(fù)責(zé)管理視圖,即 Swing 控件或者控件組,同時(shí)響應(yīng)用戶的操作。本例中的 LoginScreenMediator 管理了 LoginScreen 這個(gè) Swing 控件。LoginScreenMediator 的 show 函數(shù)的工作首先初始化 LoginScreen,LoginScreen 就是我們顯示給用戶看的 JDialog 子類,其中有兩個(gè) JLabel,一個(gè) JText Field,一個(gè) JPassword Field 和一個(gè)按鈕,這里就不列出 LoginScreen 的代碼,可以在附件中的源碼查看詳細(xì)代碼。
LoginScreenMediator 的 show 函數(shù)然后注冊(cè)了 Login 按鈕的 ActionEvent 事件,然后就顯示了 LoginScreen 控件。到此為止,用戶界面的顯示工作就完成了。LoginScreenMediator 類中另外一個(gè)需要注意的地方是 listNotificationInterests,在這個(gè)方法中該類說(shuō)明了它所關(guān)注的 Notification:LOGIN_SUCCESSFUL 和 LOGIN_FAIL。以后一旦有出現(xiàn)了這兩個(gè) Notification,LoginScreenMediator 類的 handleNotification 函數(shù)就會(huì)被調(diào)用。
下面我們來(lái)看用戶事件處理部分,界面顯示之后,一旦用戶點(diǎn)擊填入用戶名和密碼,然后點(diǎn)擊 Login 按鈕,就會(huì)觸發(fā) LoginScreenMediator 的 public void actionPerformed(ActionEvent e) 函數(shù),在這個(gè)函數(shù)中只是獲取用戶名和密碼,然后把得到的信息,通過 SUBMIT_LOGIN 這個(gè) Notification 發(fā)送出去,因?yàn)楸绢惖墓ぷ髦皇秦?fù)責(zé)管理 View,具體如何驗(yàn)證登陸信息則不是它關(guān)注的范圍,自然有其他 Command 處理。
在前面的 LoginFacade 中注冊(cè)了一個(gè) LoginCommand 類來(lái)處理 SUBMIT_LOGIN 這種類型的 Notification,下面是 LoginCommand 的源碼。
|
LoginCommand 接收到 Notification 之后,首先獲取其中的附加信息(用戶名和密碼),然后通過系統(tǒng)中已經(jīng)注冊(cè)的 UsersProxy 來(lái)檢查用戶名和密碼是否,如果正確,就發(fā)送 LOGIN_SUCCESSFUL 的 Notification,否則就發(fā)送 LOGIN_FAIL 的 Notification。本例中 UsersProxy 的功能非常簡(jiǎn)單,只是檢查一個(gè)內(nèi)存中 map,看看接收的用戶名和密碼,是否和已經(jīng)保存在 map 中預(yù)設(shè)值數(shù)據(jù)是否一致,實(shí)際上,這里也可以通過檢查 LDAP 或者數(shù)據(jù)庫(kù)之類的 UserStore 來(lái)執(zhí)行,效果是類似的。
下面我們看 LOGIN_SUCCESSFUL 和 LOGIN_FAIL 的 Notification 的處理,前面提到 LoginScreenMediator 類關(guān)注這兩個(gè) Notification,所以它會(huì)在 handleNotification 函數(shù)中處理這兩個(gè) Notification,限于示例,程序的功能就只是給用戶提示一個(gè)登陸成功或失敗的消息。
以上就是演示代碼的所有功能,從基本的代碼結(jié)構(gòu)來(lái)看,類比較多,但是大家可以看到每個(gè)類都很簡(jiǎn)單,職責(zé)也很清楚,同時(shí)每個(gè) Command、Proxy 和 Mediator 類之間的耦合度很小,Mediator 和 Proxy 甚至都不知道對(duì)方的存在,也依賴 Command 類,這樣一來(lái),Proxy 和 Mediator 的復(fù)用程度變高了。
另外 Notification 機(jī)制,大家可以看到程序有很強(qiáng)的類似工作流的性質(zhì),其實(shí)在實(shí)際使用過程中,完全可以根據(jù)需求分析的結(jié)果,結(jié)合工作流來(lái)定義 Notification。 Notification 和 Swing 事件不一樣,它不關(guān)注于用戶的鍵盤等 UI 事件,它關(guān)注業(yè)務(wù)流程,所以也是一個(gè)非常有力幫助需求人員和設(shè)計(jì)人員之間的溝通。
PureMVC 框架作為一個(gè)成熟的通用框架,具有以下優(yōu)點(diǎn):
從上面的介紹中,我們可以看到,在一個(gè)項(xiàng)目中根據(jù)實(shí)際情況整合 PureMVC 框架,可以讓可以使得和 UI(不限于 Swing)相關(guān)部分設(shè)計(jì)更簡(jiǎn)潔,并提供更多的可復(fù)用組件,增強(qiáng)需求和設(shè)計(jì)之間的溝通效果,有效提高項(xiàng)目的設(shè)計(jì)質(zhì)量。
描述 | 名字 | 大小 | 下載方法 |
---|---|---|---|
本文樣例代碼 | Login.zip | 6 KB | HTTP |
學(xué)習(xí)
討論
聯(lián)系客服