這是一份全面 & 清晰的架構設計指南:MVC、MVP & MVVM模式(含實例講解)
- 2019 年 10 月 25 日
- 筆記
版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/carson_ho/article/details/100070713
前言
- 在
Android
開發中,當你梳理完需求後,你要做的並不是馬上寫下你的第一行代碼,而是需先設計好整個項目的技術框架 - 今天,我將全面介紹
Android
開發中主流的技術框架MVC
、MVP
與MVVM
模式,並實例講解MVP
模式,希望您們會喜歡。
目錄

1. 為什麼要進行技術框架的設計
- 模塊化功能 使得程序模塊化,即:內部的高聚合、模塊之間的低耦合
- 提高開發效率 開發人員只需專註於某一點(視圖顯示、業務邏輯 / 數據處理)
- 提高測試效率 方便後續的測試 & 定位問題
切記:不要為了設計而設計,否則反而會提高開發量

2. Android開發主流的技術框架
- 主要有
MVC
、MVP
、MVVM
3種模式 - 下面,我將詳細 & 具體的介紹上述3種模式
2.1 MVC模式
- 角色說明

- 模式說明

- 該模式存在的問題:Activity責任不明、十分臃腫
Activity
由於其生命周期的功能,除了擔任View
層的部分職責(加載應用的布局、接受用戶操作),還要承擔Controller
層的職責(業務邏輯的處理) 隨着界面的增多 & 邏輯複雜度提高,Activity
類的代碼量不斷增加,越加臃腫
2.2 MVP模式
- 出現的原因 為了解決上述
MVC
模式存在的問題,把分離Activity
中的View
層 和Controller
層的職責,從而對Activity代碼量進行優化、瘦身,所以出現了MVP
模式 - 角色說明

- 模式說明

- 優點:(對比MVC模式)
- 耦合度更低:通過
Presenter
實現數據和視圖之間的交互,完全隔離了View層與Mode層,二者互不干涉
避免了
View
、Model
的直接聯繫,又通過Presenter
實現兩者之間的溝通
Activity
代碼變得更加簡潔:簡化了Activity
的職責,僅負責UI相關操作,其餘複雜的邏輯代碼提取到了Presenter
層中進行處理
2.3 MVVM
為了更加分離M、V層,更加釋放Activity的壓力,於是出現了MVVM模式
- 定義
VM
層:ViewModel
,即 View的數據模型和Presenter的合體
基本上與
MVP
模式完全一致,將邏輯處理層Presenter
改名為ViewModel
- 模式說明

- 優點 使得視圖層
(View)
& 控制層(Controller)
之間的耦合程度進一步降低,關注點分離更為徹底,同時減輕了Activity
的壓力
本文主要講解MVC和MVP模式,不過多闡述MVVM模式.
3. MVC、MVP模式的區別

4. 三種模式出現的初衷
MVC
模式的出現 為解決程序模塊化問題,於是MVC模式出現了:將業務邏輯、數據處理與界面顯示進行分離來組織代碼,即分成M、V、C層;MVP
模式的出現 但M、V層還是有相互交叉、隔離度不夠,同時寫到Activity上使得Activity代碼臃腫,於是出現了MVP: 隔離了MVC中的 M 與 V 的直接聯繫,將M、V層更加隔離開來,並釋放了Activity的壓力;MVVM
模式的出現 為了更加分離M、V層,更加釋放Activity的壓力,於是出現了MVVM: 使得V和M層之間的耦合程度進一步降低,分離更為徹底,同時更加減輕了Activity的壓力。
下面,我將詳細講解一下最常用的MVP
模式的核心思想 & 使用
5. MVP模式詳解
此處主要詳細分析MVP模式的核心思想,並實例說明。
5.1 核心思想
把Activity里的邏輯都抽離到View
和Presenter
接口中去 & 由具體的實現類來完成。具體實現思路如下:
- 把
Activity
中的UI
邏輯抽象成View
接口 & 由具體的實現類來完成 - 把業務邏輯抽象成
Presenter
接口 & 由具體的實現類來完成 Model
類還是原來MVC
模式的Model
層
5.2 實現步驟
MVP
模式的UML
圖

通過UML
圖可看出,使用MVP
模式的步驟如下:

5.3 實例講解
本節通過一個 英語詞典app
實例 講解 MVP
模式具體的實現
前言:工程項目的列表架構
MVP
技術架構的項目結構非常清晰:把M
、V
、P
層分別分為三個文件夾:Model
、View
、Presenter
,每個文件下分別是對應的接口和實現的類
其中
Model
層的fanyi
類是作為實現用GSON
解析JSON
信息的一個JavaBean
步驟1:設置View層(IView接口 & 實現類)
/** * View接口:IfanyiView * 需定義在實現類中需要用到的方法 */ public interface IfanyiView { void init();//初始化 void SetInfo(String str); //輸出翻譯信息 void SetError(); //輸出出錯信息 } /** * View實現類:MainActivity類 * 註:由於MainActivity是對應View層的實現類,所以要實現View層的接口 */ public class MainActivity extends AppCompatActivity implements IfanyiView { private EditText et; private TextView tv; CidianPresenter cidianPresenter; // 聲明了Presenter對應類 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 實例化P對應類的對象和findView init(); // 接受用戶的輸入 findViewById(R.id.btnfanyi).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //將View層獲得的數據傳入Presenter層 ,注意還要傳遞MainActivity cidianPresenter.InputToModel(et.getText().toString(), MainActivity.this); } }); } @Override public void init(){ //實例化P類的對象和findView cidianPresenter = new CidianPresenter(this); et = (EditText) findViewById(R.id.editText); tv = (TextView) findViewById(R.id.tv); } @Override //輸出出錯信息 public void SetError() { tv.setText("查詢不成功,請檢查網絡"); } //輸出翻譯信息 @Override public void SetInfo(String str){ tv.setText(str); } } // 從上述代碼可看出,MainActivity只做了FindView、setListener的工作(包含了cidianPresenter),簡潔清爽!
步驟2:設置Presenter層(創建IPresenter接口&實現類)
/** * Presenter接口:ICidianPresenter * 需定義在實現類中需要用到的方法 */ public interface ICidianPresenter { void InputToModel(String input,Context context); // 將View層獲得的數據傳入Model層 } /** * Presenter層的實現類:CidianPresenter類 * 註:由於CidianPresenter是對應Presenter層的實現類,所以要實現Presenter層的接口 */ public class CidianPresenter implements onfanyiListener,ICidianPresenter { // 1. 聲明View層對應接口、Model層對應的類 IfanyiView fyV; fanyimodel fanyimodel; // 2. 重構函數,初始化View接口實例、Model實例 public CidianPresenter(IfanyiView fyV){ this.fyV = fyV; fanyimodel = new fanyimodel(); } // 3.將View層獲得的數據傳入Model層,注意要傳遞this.當前類 @Override public void InputToModel(String input, Context context){ fanyimodel.HandleData(input, context, this); } // 回調函數,調用UI更新 @Override public void onSuccess(String str) { fyV.SetInfo(str); } // 回調函數,調用UI輸出出錯信息 @Override public void onError() { fyV.SetError(); } } // 註: // a. 保留IfanyiView的引用,就可直接在CidianPresenter當前類進行UI操作而不用在Activity操作 // b. 保留了Model層的引用就可以將View層的數據傳遞到Model層
步驟3:Model層(Model層接口 & 實現類)
/** * Model層接口:Ifanyi * 需定義在實現類中需要用到的方法 */ public interface Ifanyi { void HandleData(String input,Context context,final onfanyiListener listener); String fanyiToString(fanyi fy); } /** * Model層的實現類:fanyiModel類 * 註:由於fanyiModel是對應Model層的實現類,所以要實現Model層的接口 */ public class fanyimodel implements Ifanyi { private fanyi fy = new fanyi(); public void HandleData(String input,Context context,final onfanyiListener listener){ // 使用Volley框架來實現異步從網絡的有道API獲取翻譯數據 RequestQueue mQueue = Volley.newRequestQueue(context); StringRequest stringRequest = new StringRequest("http://fanyi.youdao.com/openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q="+input, new Response.Listener<String>() { @Override public void onResponse(String s) { // 用Gson方式解析獲得的json字符串 Gson gson = new Gson(); fy = gson.fromJson(s.trim(),fy.getClass()); // 回調監聽器的函數把處理數據後的結果(翻譯結果)返回給Presenter層 listener.onSuccess(fanyiToString(fy)); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { listener.onError(); } }); mQueue.add(stringRequest); } public String fanyiToString(fanyi fy){ // 處理解析後的json數據,轉成UI輸出的字符串 String strexplain = "解釋:"; String strphonetic = "發音:"; String strweb = "網絡釋義:"; if (fy.basic == null){return "你所查找的還沒有準確翻譯";} for (int i = 0; i<fy.basic.explains.length; i++){ strexplain +=fy.basic.explains[i]+"n"; if (i != fy.basic.explains.length-1 ) {strexplain +="tttt";} } strphonetic += fy.basic.phonetic +"n"; for (int i = 0; i<fy.web.size(); i++){ for(int j = 0; j<fy.web.get(i).value.length;j++) { strweb += fy.web.get(i).value[j]+","; } strweb += fy.web.get(i).key+"n"; strweb += "ttttttt"; } return strexplain+"n"+strphonetic+"n"+strweb; } }
至此,關於MVP
模式的實例講解,講解完畢。
6. 總結
- 本文主要講解了
Android
開發中主流的技術框架MVC
、MVP
與MVVM
模式 - 下面我將繼續對
Android
中的知識進行深入講解