現(xiàn)在開發(fā)應用程序經(jīng)常使用一些所見即所得的開發(fā)環(huán)境,使得用戶界面的制作非常方便。然而,用戶界面是最容易發(fā)生需求變更的部分,用戶界面發(fā)生變化,經(jīng)常對業(yè)務模塊產(chǎn)生影響。并且,用戶界面是不利于自動測試的。一旦某些代碼依賴用戶界面,這樣的代碼就很難在別的模塊中調(diào)用了,因此業(yè)務邏輯不能在界面層次中進行,否則會造成不能復用,不能復用自然會增加復制粘貼的代碼,造成錯誤的擴散,放大需求變更的影響。在程序設計中,應該盡量做到用戶界面和底層的業(yè)務模型分離。
用戶界面和業(yè)務模塊的互動方式,在程序設計中經(jīng)常采用MVC模式。MVC模式并不是一個特別的模式,而是一些特定模式的組合?;旧习ㄈ齻€對象:業(yè)務模塊(Model)、用戶界面(View)和控制器(Controller),關(guān)系如下:
圖中實線表示高耦合的依賴關(guān)系,虛線表示低耦合的消息關(guān)系。業(yè)務模塊是不依賴用戶界面的,這樣就隔離了用戶界面的變更對業(yè)務程序的影響。用戶界面負責收集用戶的輸入,顯示用戶需要的數(shù)據(jù);控制器負責將用戶的請求調(diào)用到實際的業(yè)務程序,也將業(yè)務程序處理的結(jié)果回送給用戶界面;業(yè)務程序具體處理業(yè)務操作。同時業(yè)務模塊可能主動發(fā)送消息到用戶界面,通知界面顯示數(shù)據(jù)。
在具體的環(huán)境下,這些因素可能發(fā)生一些變化。比如,在web開發(fā)中,由于web應用程序的性質(zhì),用戶界面是在瀏覽器上運行的,而界面的控制和業(yè)務模塊在瀏覽器上運行,所以在web應用中通常采用這種典型的MVC模式。并且在Web應用中,不存在服務器主動向客戶端“推”數(shù)據(jù),因此從Model到View之間的虛線也是不存在的。在windows窗體程序中,控制器和界面經(jīng)常是合并在一起的,比如MFC框架中使用的Document-View模式,其中的Document對應MVC中的Model,負責保存業(yè)務數(shù)據(jù),處理業(yè)務邏輯,View相當于MVC中的View+Controller,負責用戶界面的顯示、用戶輸入的收集和畫面的跳轉(zhuǎn)控制。
好的設計和壞的設計有時候需要寫的代碼是一樣多的,但是這些代碼放的位置不一樣。MVC中最重要的一點就是清楚Controller應該處于什么樣的地位,應該完成什么樣的功能。下面用一個web應用程序的例子來說明一下。
Jsp編程有一些MVC的框架,比如Struts,Struts控制器的工作如下:首先是一個請求分派機制,負責監(jiān)聽請求和分配請求,然后是一個Command模式的實現(xiàn),負責處理請求。首先收到服務器收到客戶端的http請求,交給控制器分析其中的地址,在一個配置文件中尋找對應的處理者(一個Action的子類),建立這個類的實例,隨后執(zhí)行其execute方法,Action類中調(diào)用業(yè)務模塊進行實際業(yè)務的處理(在處理之前進行必要的準備,比如分析請求的參數(shù),將其轉(zhuǎn)化為業(yè)務模型了解的對象),得到處理結(jié)果,根據(jù)處理的結(jié)果決定需要顯示的View。這個需要顯示的View在Struts框架中也是在文件中配置的。
這是一種集中式的控制器,應用程序使用一個統(tǒng)一的Controller。不僅使業(yè)務和界面分離開,并且界面的流程完全由同一個對象來控制。最重要的是,使得功能的修改和追加變得比較方便,控制器成為業(yè)務模塊的緩沖,減輕了需求變化對業(yè)務模塊的影響。
很多windows窗體程序也采用這樣的控制器。有一個開放源碼的.Net開發(fā)工具,叫做SharpDev,本身也是用c#開發(fā)的,采用的就是這樣的集中控制方式。SharpDev是用add-in的方式進行增量開發(fā)的,程序中的功能,如打開文件、保存文件、運行某個向?qū)У裙δ芏际且粋€個獨立的add-in,使用了Command模式。程序運行過程大致如下:應用程序初始化的時候,讀取配置文件中所有名稱為*.add-in的文件,得到程序中所有的add-in,可以把這些add-in看作一個ICommand接口的實現(xiàn)。根據(jù)配置文件建立這些ICommand的實例,綁定在對應的菜單項和工具欄按鈕上。當用戶點擊這些菜單項和工具欄按鈕的時候,由一個任務分派的對象將請求定位到一個Command上,執(zhí)行其Run方法。Command執(zhí)行的時候可能要調(diào)用業(yè)務程序,業(yè)務程序是通過一系列的Service對外提供功能的,不直接向外界暴露。Controller就是負責定向用戶操作到具體Command的分派器。
窗體應用程序還有一個特點:有時候業(yè)務改變的時候,需要用戶界面作出相應的變化。比如:當代碼編輯器中的文字發(fā)生變更的時候,工具欄上的保存按鈕要置為可用狀態(tài),當保存后,保存按鈕又要置為灰色。這樣的功能是通過一個Observeor模式來實現(xiàn)的,這就避免了業(yè)務模塊對用戶界面的依賴,并且這樣的模式也便于同時將消息發(fā)送給多個對象,比如保存按鈕不僅要在工具欄上出現(xiàn),也要在菜單上出現(xiàn),這樣的變化是不會影響業(yè)務模塊的。在SharpDev中,這個交互的過程也是在業(yè)務模塊對外提供的Service中通過delegate來實現(xiàn)的。
很多應用程序采用的是另一種控制模式:每個畫面和窗口使用自己的控制器。在窗體程序中,這樣的方式實際上就將用戶界面和控制器融合在一起了,比如MFC中的Document-View,View不僅實現(xiàn)用戶數(shù)據(jù)的展示和輸入數(shù)據(jù)的收集,還要將用戶的輸入進行基本的處理,轉(zhuǎn)變?yōu)闃I(yè)務模塊了解的類型,調(diào)用業(yè)務模塊進行處理,最后跳轉(zhuǎn)到別的窗口。
在ASP.NET中使用code behide的編程框架,實際上也是為每一個用戶界面采用了一個獨立的Controller,aspx文件就是用戶界面,對應的code behide代碼就是他的控制器。這樣的框架減少了程序的靈活性,但是在一般情況下可以使應用程序的框架變得簡單和直接。
原文出處:
http://www.cnblogs.com/lane_cn/articles/155254.html