這是一份全面 & 清晰的架構設計指南:MVC、MVP & MVVM模式(含實例講解)

  • 2019 年 10 月 25 日
  • 筆記

版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。

本文鏈接:https://blog.csdn.net/carson_ho/article/details/100070713

前言

  • Android開發中,當你梳理完需求後,你要做的並不是馬上寫下你的第一行代碼,而是需先設計好整個項目的技術框架
  • 今天,我將全面介紹Android開發中主流的技術框架MVCMVPMVVM模式,並實例講解MVP模式,希望您們會喜歡。

目錄


1. 為什麼要進行技術框架的設計

  • 模塊化功能 使得程序模塊化,即:內部的高聚合模塊之間的低耦合
  • 提高開發效率 開發人員只需專註於某一點(視圖顯示、業務邏輯 / 數據處理)
  • 提高測試效率 方便後續的測試 & 定位問題

切記:不要為了設計而設計,否則反而會提高開發量


2. Android開發主流的技術框架

  • 主要有MVCMVPMVVM 3種模式
  • 下面,我將詳細 & 具體的介紹上述3種模式

2.1 MVC模式

  • 角色說明
  • 模式說明
  • 該模式存在的問題:Activity責任不明、十分臃腫 Activity由於其生命周期的功能,除了擔任View層的部分職責(加載應用的布局、接受用戶操作),還要承擔Controller層的職責(業務邏輯的處理) 隨着界面的增多 & 邏輯複雜度提高,Activity類的代碼量不斷增加,越加臃腫

2.2 MVP模式

  • 出現的原因 為了解決上述MVC模式存在的問題,把分離Activity中的View層 和 Controller層的職責,從而對Activity代碼量進行優化、瘦身,所以出現了MVP模式
  • 角色說明
  • 模式說明
  • 優點:(對比MVC模式)
  1. 耦合度更低:通過Presenter實現數據和視圖之間的交互,完全隔離了View層與Mode層,二者互不干涉

避免了ViewModel的直接聯繫,又通過Presenter實現兩者之間的溝通

  1. 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里的邏輯都抽離到ViewPresenter接口中去 & 由具體的實現類來完成。具體實現思路如下:

  1. Activity中的UI邏輯抽象成View接口 & 由具體的實現類來完成
  2. 把業務邏輯抽象成Presenter接口 & 由具體的實現類來完成
  3. Model類還是原來MVC模式的Model

5.2 實現步驟

MVP模式的UML

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

5.3 實例講解

本節通過一個 英語詞典app實例 講解 MVP模式具體的實現

前言:工程項目的列表架構

MVP技術架構的項目結構非常清晰:把MVP層分別分為三個文件夾:ModelViewPresenter,每個文件下分別是對應的接口和實現的類

其中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開發中主流的技術框架MVCMVPMVVM模式
  • 下面我將繼續對 Android中的知識進行深入講解