Android開發(fā)模式之MVC

一、 什么是MVC

MVC全名是Model View Controller,是模型(model)-視圖(view)-控制器(controller)的縮寫谦屑,一種軟件設計典范。

  • 模型(Model)—— 是應用程序中用于處理應用程序數據邏輯的部分篇梭。通常模型對象負責在數據庫中存取數據
  • 視圖(View)—— 是應用程序中處理數據顯示的部分氢橙。通常視圖是依據模型數據創(chuàng)建的。
  • 控制器(Controller)—— 是應用程序中處理用戶交互的部分恬偷。通澈肥郑控制器負責從視圖讀取數據,控制用戶輸入袍患,并向模型發(fā)送數據坦康。

如圖:

MVC設計模式

二、 Android中的MVC

  • 模型層(Model):負責數據處理相關的邏輯诡延,通知View改變滞欠,會常涉及到網絡請求及Android中的datebase、SharePreference等

  • 視圖層(View):自定義View或ViewGroup肆良,負責將用戶的請求通知Controller筛璧,并根據model更新界面

  • 控制層(Controller):接收用戶請求并更新model

代碼案例:Login MVC

  • Model
/**  模型層 ——— 登錄接口  **/
public interface ILoginModel {    
     void login(String username, String password, LoginCallBack callBack);
}
/**  模型層 ——— 完成具體的數據操作。  **/
public class LoginModel implements ILoginModel {    

     @Override    
     public void login(String username, String password, LoginCallBack callBack) {        
        if (username.equals("MVC") && password.equals("MVC")){            
            callBack.onLoginSuccess();        
        }else{            
            callBack.onLoginFail();        
        }    
     }
}
  • View
/**  視圖層 ——— 視圖操作接口     **/
public interface ILoginView {    

     String getUsername();    
     String getPassword();    

     void initView();    
     void setViewClickListener(View.OnClickListener onclikLister);    

     void onUsernameEmpty();   // 用戶名為空時的顯示操作    
     void onPasswordEmpty();   // 密碼為空時的顯示操作    
     void onLoginSuccess();   // 登陸成功時的顯示操作    
     void onLoginFail();   // 密碼失敗時的顯示操作
}
/**  視圖層 ——— 只是作為接受用戶數據和展示數據的方式     **/
public class LoginView extends LinearLayout implements ILoginView{  
  
     private Context context;    
     private EditText mUsername;    
     private EditText mPassword;    
     private Button mLoginBtn;    

     public LoginView(Context context, AttributeSet attrs) {        
        super(context, attrs);        
        this.context = context;    
     }    
    
     @Override
     public void initView(){        
        mUsername = (EditText) findViewById(R.id.et_username);        
        mPassword = (EditText) findViewById(R.id.et_password);        
        mLoginBtn = (Button) findViewById(R.id.btn_login);    
     }    

     @Override
     public String getUsername(){        
        return mUsername.getText().toString();    
     }    

     @Override
     public String getPassword(){        
        return mPassword.getText().toString();    
     }     

     @Override
     public void setViewClickListener(OnClickListener onclikLister){        
        mLoginBtn.setOnClickListener(onclikLister);    
     }

     @Override
     public void onUsernameEmpty() {        
        Toast.makeText(context, "用戶名不能為空", Toast.LENGTH_SHORT).show();    
     } 

     @Override
     public void onPasswordEmpty() {        
        Toast.makeText(context, "密碼不能為空", Toast.LENGTH_SHORT).show();    
     }

     @Override
     public void onLoginSuccess() {        
        Toast.makeText(context, "登錄成功", Toast.LENGTH_SHORT).show();    
     }

     @Override
     public void onLoginFail() {       
        Toast.makeText(context, "登錄失敗", Toast.LENGTH_SHORT).show();    
     }
}
  • Controller
public class LoginController implements View.OnClickListener {    

     private ILoginView loginView;    
     private ILoginModel loginModel;    
  
     public LoginController(ILoginView loginView){        
        this.loginView = loginView;        
        loginModel = new LoginModel();    
     }

     @Override 
     public void onClick(View v) {        
        switch (v.getId()){            
           case R.id.btn_login:                
              String username = loginView.getUsername();                
              String password = loginView.getPassword();                
              if (TextUtils.isEmpty(username)){                    
                   loginView.onUsernameEmpty();                
              }else if (TextUtils.isEmpty(password)){                    
                   loginView.onPasswordEmpty();                
              }                
              // 調用模型層去處理具體的請求
              loginModel.login(username, password, new LoginCallBack() {                    
                  @Override                    
                  public void onLoginSuccess() {     
                     //  模型層完成數據處理后,通知視圖層做出相應的改變,用戶得到反饋                
                     loginView.onLoginSuccess();                    
                  }                    
                  @Override                    
                  public void onLoginFail() {                        
                     loginView.onLoginFail();                    
                  }                
              });                
              break;        
         }   
     }
} 
  • else
/**  此時Activity就變?yōu)榱顺休d視圖層的容器惹恃。 **/
public class MainActivity extends AppCompatActivity {    

     private LoginController controller;    
     private LoginView loginview;    

     @Override    
     protected void onCreate(Bundle savedInstanceState) {        
        super.onCreate(savedInstanceState);        
        setContentView(R.layout.activity_main);        
        initController();    
     }    

     private void initController(){        
        loginview = (LoginView) findViewById(R.id.loginview);        
        loginview.initView();        
        controller = new LoginController(loginview);       
        loginview.setViewClickListener(controller);    
     }
}
<!--  將LoginView作為父容器  -->
<com.scnu.zhou.mvc.view.LoginView 
      xmlns:android="http://schemas.android.com/apk/res/android"    
      android:layout_width="match_parent"    
      android:layout_height="match_parent"    
      android:paddingBottom="@dimen/activity_vertical_margin"    
      android:paddingLeft="@dimen/activity_horizontal_margin"    
      android:paddingRight="@dimen/activity_horizontal_margin"    
      android:paddingTop="@dimen/activity_vertical_margin"    
      android:orientation="vertical"    
      android:id="@+id/loginview">    

      <EditText        
          android:id="@+id/et_username"        
          android:layout_width="match_parent"        
          android:layout_height="wrap_content"        
          android:inputType="text"/>    

      <EditText        
          android:id="@+id/et_password"        
          android:layout_width="match_parent"        
          android:layout_height="wrap_content"        
          android:layout_marginTop="10dp"        
          android:inputType="textPassword"/>    

      <Button        
          android:id="@+id/btn_login"        
          android:layout_width="match_parent"        
          android:layout_height="50dp"        
          android:text="Login"        
          android:layout_marginTop="10dp"/>
</com.scnu.zhou.mvc.view.LoginView>

三夭谤、 MVC模式的優(yōu)缺點

優(yōu)點:

  • 耦合性低 —— 視圖層和業(yè)務層分離,這樣就允許更改視圖層代碼而不用重新編譯模型和控制器代碼
  • 重用性高 —— 多個視圖能共享一個模型
  • 生命周期成本低 —— MVC使開發(fā)和維護用戶接口的技術含量降低座舍。

缺點:

  • 增加了系統(tǒng)結構和實現的復雜性 —— 對于簡單的界面沮翔,嚴格遵循MVC陨帆,使模型曲秉、視圖與控制器分離采蚀,會增加結構的復雜性,并可能產生過多的更新操作承二,降低運行效率榆鼠。
  • 視圖與控制器間的連接過于緊密 —— 視圖與控制器是相互分離,但卻是聯(lián)系緊密的部件亥鸠,視圖沒有控制器的存在妆够,其應用是很有限的,反之亦然负蚊,這樣就妨礙了他們的獨立重用神妹。
  • 視圖對模型數據的低效率訪問 —— 依據模型操作接口的不同,視圖可能需要多次調用才能獲得足夠的顯示數據家妆。對未變化數據的不必要的頻繁訪問鸵荠,也將損害操作性能。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末伤极,一起剝皮案震驚了整個濱河市蛹找,隨后出現的幾起案子,更是在濱河造成了極大的恐慌哨坪,老刑警劉巖庸疾,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異当编,居然都是意外死亡届慈,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進店門凌箕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拧篮,“玉大人,你說我怎么就攤上這事牵舱〈ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵芜壁,是天一觀的道長。 經常有香客問我慧妄,道長,這世上最難降的妖魔是什么塞淹? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮饱普,結果婚禮上运挫,老公的妹妹穿的比我還像新娘状共。我一直安慰自己谁帕,他們只是感情好,可當我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布匈挖。 她就那樣靜靜地躺著碾牌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪儡循。 梳的紋絲不亂的頭發(fā)上舶吗,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天择膝,我揣著相機與錄音,去河邊找鬼调榄。 笑死,一個胖子當著我的面吹牛筐带,可吹牛的內容都是我干的。 我是一名探鬼主播伦籍,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼腮出,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了胚嘲?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤攻锰,失蹤者是張志新(化名)和其女友劉穎妓雾,沒想到半個月后娶吞,有當地人在樹林里發(fā)現了一具尸體械姻,經...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年毫缆,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡浸颓,死狀恐怖,靈堂內的尸體忽然破棺而出棵磷,到底是詐尸還是另有隱情,我是刑警寧澤仪媒,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布谢鹊,位于F島的核電站,受9級特大地震影響佃扼,放射性物質發(fā)生泄漏。R本人自食惡果不足惜压昼,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一瘤运、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拯坟,春花似錦、人聲如沸郁季。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽塞琼。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間牵咙,已是汗流浹背攀唯。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留侯嘀,地道東北人。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓吠谢,卻偏偏與公主長得像诗茎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子敢订,可洞房花燭夜當晚...
    茶點故事閱讀 43,658評論 2 350

推薦閱讀更多精彩內容