一文帶你全面瞭解MVC、MVP、MVVM模式(含實例講解)


前言

  • 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 +="\t\t\t\t";}
          }
          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 += "\t\t\t\t\t\t\t";
          }
          return strexplain+"\n"+strphonetic+"\n"+strweb;
      }
  }

至此,關於MVP模式的實例講解,講解完畢。


6. 總結

  • 本文主要講解了Android開發中主流的技術框架MVCMVPMVVM模式
  • 下面我將繼續對 Android中的知識進行深入講解 ,有興趣可以繼續關注Carson_Ho的安卓開發筆記

請點贊!因爲你的鼓勵是我寫作的最大動力!

相關文章閱讀
Android開發:最全面、最易懂的Android屏幕適配解決方案
Android事件分發機制詳解:史上最全面、最易懂
Android開發:史上最全的Android消息推送解決方案
Android開發:最全面、最易懂的Webview詳解
Android開發:JSON簡介及最全面解析方法!
Android四大組件:Service服務史上最全面解析
Android四大組件:BroadcastReceiver史上最全面解析


歡迎關注Carson_Ho的簡書!

不定期分享關於安卓開發的乾貨,追求短、平、快,但卻不缺深度

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章