MVC模式在j2me項目中的應用(一)

來源:互聯網
上載者:User
項目 MVC模式在j2me項目中的應用(一)
作者:FavoYang Email:favoyang@yahoo.com 歡迎交流
Keywords:MVC j2me UI模式

內容提要:
本文簡要的介紹了MVC模式的思想,並分析了MVC模式的利弊,最後結合MIDP平台給出幾種常見的MVC模式實踐。相信此文對任何一個使用midp平台的商務程式開發人員都或多或少的有所協助。

著作權聲明:
本文同時發表在www.j2medev.com和我的Blog(blog.csdn.net/alikeboy)上,如果需要轉載,有三個途徑:1)聯絡我並經我同意;2)和www.j2medev.com有轉載文章合作協議的 3)通過Rss彙總我的Blog。另外網上轉載需要全文轉寄(包括文章的頭部的聲明),不要斷章取義。

本文:

初識MVC模式
第一次認識到MVC模式是從Microsoft MFC架構所採用的“文檔-視圖”模型開始的。第一次接觸到這個概念讓我興奮不已,很長時間困擾我的程式架構問題似乎迎刃而解了。而後我翻閱了GOF一書中對MVC模式的描述,增進了對這個模式的一些理解。應該說MVC架構是程式設計領域的常青樹,也是GOF模式中最為重要的模式之一。這一經典的模式被廣泛的使用,有太多的程式構架在這一架構之下,從早期的卓面Application到現在流行的Web。並因各自的需求不同,MVC有了很多的變種。瞭解MVC是每個程式設計人員的必修課,最好能夠達到熟練運用的程度。

我並不打算詳細介紹這一模式,因為細節比較複雜,我口舌拙笨也不容易說清楚,大家應該參閱一下有關模式的書籍,任何一本都比我要講的清楚。所以此處就一帶而過。MVC模式是Model-View-Controller的縮寫,中文譯為“模型-視圖-控制器”。MVC的核心思想是分離。Model就是對實體類的抽象;View就是Model在螢幕上的表示;Controller就是協調者。可能有朋友發現Controller的描述多少有些含糊,不要著急,這個一會還要談到。大概因為太過有名,MVC模式的每個實現都出處很大,但他們卻都叫做MVC!!搞得初學者一頭霧水。往往濫用,最後搞得M.V.C.三者之間的協調很混亂。這其實並不是他們的錯,理清思路的關鍵還是剛剛提到的一個詞“分離”。儘管MVC實現不同,但是思想是一致的。

MVC模式的利與弊
先談優點:
1)將M.V.C.分離可以讓不同的專家負責不同的模組,一般情況下,M部分由熟悉資料庫,網路傳輸的專家來負責;V則交給對UI有研究的專家。這對於項目的管理者而言是多麼的誘人,分工意味著可以提高效率並可以按照傳統的責任劃分來處理軟體開發過程。對開發人員而言也可以專心於一個領域。這樣做的前提是介面要明確,MVC的分離思想正為其提供了基礎。
2)一旦V的部分發生變化,可以迅速的重構而不必引起整個工程的返工。如今的軟體表現層的部分變化實在是太快了…
3)M的部分,因為足夠抽象,可以方便的重複利用,符合OO的思想。另一方面我們可以利用JUnit等單元測試工具對M進行測試,保證工程品質。

談完了優點再來看看缺點:
1)利用MVC模式(也包括近代的其他一些模式)暗示我們通過多產生一些類,來提高程式的可讀性與健壯性。附帶來的缺點就是類的數量的膨脹。說句笑話,MVC就好像是發麵時用的速效粉一樣,是最為方便的代碼膨脹劑,相信大家都深有體會:)
2)MVC雖然定義了M.V.C.個個組件的含義,但並不具體,而且沒有非常明確的固定三者之間的聯絡。所以一直以來除了View沒有爭論外,其他方面都有很多爭論,大家都想把自己的理解作為正解。尤其是“Model到底是螢幕資料的集合還是實體資料”、“控制器的作用”是兩個經常爭論的問題。前面提過MVC變種很多,這也給初學者留下了不少的陷阱。後面結合執行個體將會分析幾種常見的做法。
3)MVC的實現成本偏高。但請注意是這是相對的,一般而言項目越大,越可以看出其優勢。


常見的MVC模式實踐
下面將會介紹在midp平台幾種常見的實踐,最後是我習慣的做法

M—V形式(或者MC—V、M—VC)

這也是在j2me中一種慣用的方法,精鍊的說這種方法是以螢幕為組織單位的,因而很適合RAD工具的開發思路。一個螢幕及其控制被抽象成一個VC類,而這個類中有一個私人的Model對象來代表螢幕上要用到的資料元素。螢幕對象並不儲存任何的實體資料,這些資料被組織在了Model對象中。大概因為螢幕對象很直觀,控制器的作用也不明晰(它絕大部分的功能被view或是model取代,具體取決於你的實現),所以也常常稱呼為model-view模式。形式如下:
class MyFrame extend Frame{
private Model model;
private StringItem name;
MyFrame(Model model){
this.model=model;
name=new StringItem(model.getName());//請求模型的資料
append(name);
}
}

class Model{
private String name="M-C pattern";
public String getName(){//這是一個服務介面
return name;
}
}
上面看到的是個典型的M—V模型,我們可以理解這種以螢幕為核心的分離的含義。Model組織起螢幕的資料,view向Model索要其希望顯示的資料,注意這一操作一定要通過預先協商好的介面訪問,而不是直接操作。如果出現複雜的事務邏輯(使用者選擇的某種操作),有人將其放在Model端,也有人放在View端,但一般上放在Model端,這時Model帶有嚴重的Controller的色彩。

這種形式的優點是非常的直觀,也有限的分離了顯示和資料。如果常看j2medev.com站長Mingjava的文章,可以看到大部分他寫的例子都是這種模式。並且這種模式也常常用於RAD工具。

這種模式的缺點是它與RAD工具一樣鼓勵你從螢幕開始思考問題,這往往讓你陷入RAD的陷阱——不先考慮事務的流程,而是從使用者介面直接下手去分析問題,這往往扼殺了你的全域構思。

Sun blueprints: Smart Ticket中使用的MVC模式

著名的藍圖程式Smart Ticket中使用了MVC模式,並且這一模式協助Sun的程式員在MIDP2發布時,快速的將Smart Ticket的view部分從MIDP1.0 更新到MIDP2.0。

Sun針對MIDP的特點,設計並改進了這一模式,在SUN的解決方案中是一個很標準的方法,只是 Controller變成了一個巨大的交易處理器,所有由UI對象收集到的使用者的需求都轉寄給Controller處理。Controller內部儲存了一組常量。在一個dispose(int id)形式的方法裡一個巨大的switch case語句根據比較不同的常量,處理不同的請求。這種技術有時也將Controller稱為處理器,或者螢幕導航器。這種模式的提出者主要是要集中處理j2me裡頻繁的畫面導航。

很多人都覺得,在j2me中將Controller改造成巨大的交易處理器是一個很好的方法。我對此持保留意見。

iFeedback 中簡化的MVC

為了大大減少類的數量,iFeedback的作者,將MVC封裝到一個類中,用不同的方法來代表對這三者的分離,這種舉動證明對減少類的數量又很大協助。
public abstract class MVCComponent implements CommandListener {
// Set from outside at beginning
public static Display display;

// Returns the screen object from the derived class
public abstract Displayable getScreen();

public Displayable prepareScreen () throws Exception {
if ( getScreen() == null ) {
initModel();
createView();
} else {
updateView();
}
getScreen().setCommandListener ( (CommandListener) this );
return getScreen ();
}

public void showScreen() {
try {
display.setCurrent( prepareScreen() );
} catch (Exception e) {
e.printStackTrace();
Alert a = new Alert("Error in showing screen");
a.setTimeout(Alert.FOREVER);
display.setCurrent(a);
}
}

// Initialize. If a data member is not backed by RMS, make sure
// it is uninitilzed (null) before you put in values.
protected abstract void initModel () throws Exception;

protected abstract void createView () throws Exception;

protected abstract void updateView () throws Exception;

public abstract void commandAction(Command c, Displayable s);

}
因為都在一個類裡面,你在也不必被MVC三者之間的關係操心了,這種退化的做法,是對MIDP有限資源的妥協。

我的習慣做法

下面結合我對MVC的理解和大家交流一下。我使用的是一種UML標準的做法,最大程度上對的體現分離的思想。首先和大家交流一下詞彙表:

View代表螢幕。
View通過預先商定好的介面向Controller索要資料,View同時收集使用者的輸入,View並不處理這些輸入,而是根據不同的輸入回調Controller不同的方法。通常View的子類使用UI尾碼。

Controller 控制器
提供View調用的介面,負責和model交流。控制器和View共同擔負起和使用者交流的作用。

Model 泛指一系列的實體物件
需要注意的是我理解的Model並不是螢幕資料的組織單位。Model代表一系列的實體物件。由Controller跟Model交流。我覺得RAD工具中常常將Model代表螢幕資料的集合正式導致MVC概念混亂的一個原因。RAD工具中Model,大體相當於這裡的Controller所起的作用。

控制器並不總是聯絡著Model,有時只是依賴關係。並且Controller往往通過Model的對應的生命期類來獲得Model對象。在這種形式中,層層隔離,View與Controller緊密相連,而Model有很高的獨立性,可以很好的重用。

一般的結合UML設計的過程,對MVC的各個類有相應的命名習慣。
View 稱為Boundary類(邊界類) 以UI結尾
Controller 稱為 Controller類(控制類) 以Workflow結尾
Model 稱為Entity類(實體類) 以Entity結尾或者沒有尾綴
Model對應的Lifecycle類(生命週期類) 以Locator結尾

邊界類和控制類的基礎類如下
BaseView.java
/**
* @author Favo
*
* 視圖類
*/
public abstract class BaseView {

public abstract Display getDisplay();

/**
* 簡單的返回封裝的螢幕對象,不要做任何準備螢幕的操作!
*/
public abstract Displayable getScreen();

/**
* 建立螢幕
*/
protected abstract void createView() throws Exception;

/**
* 更新螢幕
*/
public abstract void updateView() throws Exception;

/**
* 返回控制器
*/
public abstract BaseController getController();

/**
* 準備螢幕
* 返回準備好的螢幕對象
*/
public Displayable prepareScreen() throws Exception {
if(getScreen()==null){
createView();
} else {
updateView();
}
return getScreen();
}

/**
* 顯示當前螢幕
*/
public void displayScreen(){
try{
getDisplay().setCurrent(prepareScreen());
} catch (Exception e) {
e.printStackTrace();
Alert al=new Alert("Error",e.toString()+'\n'+e.getMessage(),null,AlertType.ERROR);
al.setTimeout(Alert.FOREVER);
getDisplay().setCurrent(al);
}
}

}

BaseController.java
/**
* @author Favo
*
* 控制類
*/
public abstract class BaseController {
public abstract BaseView getView();
public abstract void setView(BaseView view);
}


注意到這些基礎的類並沒有向MFC架構那樣產生完整的架構,而是設計成了抽象類別,一來希望強迫大家實現抽象類別(防止出錯);二來希望增加一點靈活性。所以兩個類之間的通訊就要靠大家撰寫的子類的建構函式了。一般我的習慣是,初始化好控制器,然後將控制器作為參數傳給邊界類的建構函式,由邊界類的建構函式來回調控制器的setView()來實現的。這些步驟是一定要有的,不然會NULLpointerExcpetion哦。

儘管理論上可能很清晰,但實踐帶來的複雜性是驚人的。這正是軟體開發的問題,太多的細節困擾這開發人員對大局的把握。本文接下來,將結合最後這種設計思想,給出一個完整的設計執行個體。協助大家從實踐的角度理解運用這一模式。敬請大家期待。



相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。