MVC,MVP设计模式

什么是MVP

  MVP是模型(Model)、视图(View)、主持人(Presenter)的缩写,分别表明项目中3个不一样的模块。html

  模型(Model):负责处理数据的加载或者存储,好比从网络或本地数据库获取数据等;java

  视图(View):负责界面数据的展现,与用户进行交互;android

  主持人(Presenter):至关于协调者,是模型与视图之间的桥梁,将模型与视图分离开来。git

  以下图所示,View与Model并不直接交互,而是使用Presenter做为View与Model之间的桥梁。其中Presenter中同时持有Viwe层以及Model层的Interface的引用,而View层持有Presenter层Interface的引用。当View层某个界面须要展现某些数据的时候,首先会调用Presenter层的某个接口,而后Presenter层会调用Model层请求数据,当Model层数据加载成功以后会调用Presenter层的回调方法通知Presenter层数据加载完毕,最后Presenter层再调用View层的接口将加载后的数据展现给用户。这就是MVP模式的整个核心过程。github

  这样分层的好处就是大大减小了Model与View层之间的耦合度。一方面可使得View层和Model层单独开发与测试,互不依赖。另外一方面Model层能够封装复用,能够极大的减小代码量。固然,MVP还有其余的一些优势,这里再也不赘述。下面看下MVP模式在具体项目中的使用。数据库

MVP模式在项目中的使用

model层描述和具体代码

提供咱们想要展现在view层的数据和具体登录业务逻辑处理的实现,设计模式

 

 

1 package com.nsu.edu.androidmvpdemo.login;
2 
3 /**
4  * Created by Anthony on 2016/2/15.
5  * Class Note:模拟登录的操做的接口,实现类为LoginModelImpl.至关于MVP模式中的Model层
6  */
7 public interface LoginModel {
8     void login(String username, String password, OnLoginFinishedListener listener);
9 }
 1 package com.nsu.edu.androidmvpdemo.login;
 2 
 3 import android.os.Handler;
 4 import android.text.TextUtils;
 5 /**
 6  * Created by Anthony on 2016/2/15.
 7  * Class Note:延时模拟登录(2s),若是名字或者密码为空则登录失败,不然登录成功
 8  */
 9 public class LoginModelImpl implements LoginModel {
10 
11     @Override
12     public void login(final String username, final String password, final OnLoginFinishedListener listener) {
13 
14         new Handler().postDelayed(new Runnable() {
15             @Override public void run() {
16                 boolean error = false;
17                 if (TextUtils.isEmpty(username)){
18                     listener.onUsernameError();//model层里面回调listener
19                     error = true;
20                 }
21                 if (TextUtils.isEmpty(password)){
22                     listener.onPasswordError();
23                     error = true;
24                 }
25                 if (!error){
26                     listener.onSuccess();
27                 }
28             }
29         }, 2000);
30     }
31 }

2.2 view层描述和具体代码

负责显示数据、提供友好界面跟用户交互就行。MVP下Activity和Fragment以及View的子类体如今了这一 层,Activity通常也就作加载UI视图、设置监听再交由Presenter处理的一些工做,因此也就须要持有相应Presenter的引用。本层所须要作的操做就是在每一次有相应交互的时候,调用presenter的相关方法就行。(好比说,button点击)网络

 1 package com.nsu.edu.androidmvpdemo.login;
 2 
 3 /**
 4  * Created by Anthony on 2016/2/15.
 5  * Class Note:登录View的接口,实现类也就是登录的activity
 6  */
 7 public interface LoginView {
 8     void showProgress();
 9 
10     void hideProgress();
11 
12     void setUsernameError();
13 
14     void setPasswordError();
15 
16     void navigateToHome();
17 }
 1 package com.nsu.edu.androidmvpdemo.login;
 2 
 3 import android.app.Activity;
 4 import android.content.Intent;
 5 import android.os.Bundle;
 6 import android.view.View;
 7 import android.widget.EditText;
 8 import android.widget.ProgressBar;
 9 import android.widget.Toast;
10 
11 import com.nsu.edu.androidmvpdemo.R;
12 
13 /**
14  * Created by Anthony on 2016/2/15.
15  * Class Note:MVP模式中View层对应一个activity,这里是登录的activity
16  */
17 public class LoginActivity extends Activity implements LoginView, View.OnClickListener {
18 
19     private ProgressBar progressBar;
20     private EditText username;
21     private EditText password;
22     private LoginPresenter presenter;
23 
24     @Override
25     protected void onCreate(Bundle savedInstanceState) {
26         super.onCreate(savedInstanceState);
27         setContentView(R.layout.activity_login);
28 
29         progressBar = (ProgressBar) findViewById(R.id.progress);
30         username = (EditText) findViewById(R.id.username);
31         password = (EditText) findViewById(R.id.password);
32         findViewById(R.id.button).setOnClickListener(this);
33 
34         presenter = new LoginPresenterImpl(this);
35     }
36 
37     @Override
38     protected void onDestroy() {
39         presenter.onDestroy();
40         super.onDestroy();
41     }
42 
43     @Override
44     public void showProgress() {
45         progressBar.setVisibility(View.VISIBLE);
46     }
47 
48     @Override
49     public void hideProgress() {
50         progressBar.setVisibility(View.GONE);
51     }
52 
53     @Override
54     public void setUsernameError() {
55         username.setError(getString(R.string.username_error));
56     }
57 
58     @Override
59     public void setPasswordError() {
60         password.setError(getString(R.string.password_error));
61     }
62 
63     @Override
64     public void navigateToHome() {
65 // TODO       startActivity(new Intent(this, MainActivity.class));
66         Toast.makeText(this,"login success",Toast.LENGTH_SHORT).show();
67 //        finish();
68     }
69 
70     @Override
71     public void onClick(View v) {
72         presenter.validateCredentials(username.getText().toString(), password.getText().toString());
73     }
74 
75 }

2.3 presenter层描述和具体代码

Presenter扮演着view和model的中间层的角色。获取model层的数据以后构建view层;也能够收到view层UI上的反馈命令后分发处理逻辑,交给model层作业务操做。它也能够决定View层的各类操做。数据结构

 1 package com.nsu.edu.androidmvpdemo.login;
 2 
 3 /**
 4  * Created by Anthony on 2016/2/15.
 5  * Class Note:登录的Presenter 的接口,实现类为LoginPresenterImpl,完成登录的验证,以及销毁当前view
 6  */
 7 public interface LoginPresenter {
 8     void validateCredentials(String username, String password);
 9 
10     void onDestroy();
11 }
 1 package com.nsu.edu.androidmvpdemo.login;
 2 
 3 /**
 4  * Created by Anthony on 2016/2/15.
 5  * Class Note:
 6  * 1 完成presenter的实现。这里面主要是Model层和View层的交互和操做。
 7  * 2  presenter里面还有个OnLoginFinishedListener,
 8  * 其在Presenter层实现,给Model层回调,更改View层的状态,
 9  * 确保 Model层不直接操做View层。若是没有这一接口在LoginPresenterImpl实现的话,
10  * LoginPresenterImpl只 有View和Model的引用那么Model怎么把结果告诉View呢?
11  */
12 public class LoginPresenterImpl implements LoginPresenter, OnLoginFinishedListener {
13     private LoginView loginView;
14     private LoginModel loginModel;
15 
16     public LoginPresenterImpl(LoginView loginView) {
17         this.loginView = loginView;
18         this.loginModel = new LoginModelImpl();
19     }
20 
21     @Override
22     public void validateCredentials(String username, String password) {
23         if (loginView != null) {
24             loginView.showProgress();
25         }
26 
27         loginModel.login(username, password, this);
28     }
29 
30     @Override
31     public void onDestroy() {
32         loginView = null;
33     }
34 
35     @Override
36     public void onUsernameError() {
37         if (loginView != null) {
38             loginView.setUsernameError();
39             loginView.hideProgress();
40         }
41     }
42 
43     @Override
44     public void onPasswordError() {
45         if (loginView != null) {
46             loginView.setPasswordError();
47             loginView.hideProgress();
48         }
49     }
50 
51     @Override
52     public void onSuccess() {
53         if (loginView != null) {
54             loginView.navigateToHome();
55         }
56     }
57 }

2.4 登录的回调接口

 1 package com.nsu.edu.androidmvpdemo.login;
 2 
 3 /**
 4  * Created by Anthony on 2016/2/15.
 5  * Class Note:登录事件监听
 6  */
 7 public interface OnLoginFinishedListener {
 8 
 9     void onUsernameError();
10 
11     void onPasswordError();
12 
13     void onSuccess();
14 }

demo的代码流程:(请参考下面的类图)

1 Activity作了一些UI初始化的东西并须要实例化对应LoginPresenter的引用和实现 LoginView的接口,监听界面动做
2 登录按钮按下后即接收到登录的事件,在onClick里接收到即经过LoginPresenter的引用把它交给LoginPresenter处理。LoginPresenter接收到了登录的逻辑就知道要登录了
3 而后LoginPresenter显示进度条而且把逻辑交给咱们的Model去处理,也就是这里面的LoginModel,(LoginModel的实现类LoginModelImpl),同时会把OnLoginFinishedListener也就是LoginPresenter自身传递给咱们的Model(LoginModel)。
4 LoginModel处理完逻辑以后,结果经过OnLoginFinishedListener回调通知LoginPresenter
5 LoginPresenter再把结果返回给view层的Activity,最后activity显示结果
请参考这张类图:架构

(3)注意:


3.1 presenter里面还有个OnLoginFinishedListener,其在Presenter层实现,给Model层回调,更改View层的状态,确保 Model层不直接操做View层。
3.2 在一个好的架构中,model层可能只是一个领域层和业务逻辑层的入口,若是咱们参考网上比较火的Uncle Bob clean architecture model层多是一个实现业务用例的交互者,在后续的文章中应该会涉及到这方面的问题,目前能力有限。暂时讲解到这里

  本项目github地址:
  https://github.com/CameloeAnthony/AndroidMVPDemo

  第二例子源码地址:https://github.com/liuling07/SimpleNews

 

什么是MVC

MVC即Model-View-Controller。M:逻辑模型,V:视图模型,C:控制器。

  MVC模式下,系统框架的类库被划分为3种:模型(Model)、视图(View)、控制器(Controller)。模型对象负责创建数据结构和相应的行为操做处理。视图对象负责在屏幕上渲染出相应的图形信息展现给用户看。控制器对象负责截获用户的按键和屏幕触摸等事件,协调Model对象和View对象。

  用户与视图交互,视图接收并反馈用户的动做;视图把用户的请求传给相应的控制器,由控制器决定调用哪一个模型,而后由模型调用相应的业务逻辑对用户请求进行加工处理,若是须要返回数据,模型会把相应的数据返回给控制器,由控制器调用相应的视图,最终由视图格式化和渲染返回的数据,对于返回的数据彻底能够增长用户体验效果展示给用户。

  一个模型能够有多个视图,一个视图能够有多个控制器,一个控制器也能够有多个模型。

MVC模式结构以下:

图1-1  MVC模式组件类型的关系和功能

  模型(Model):封装的是数据源和全部基于对这些数据的操做。在一个组件中,Model每每表示组件的状态和操做状态的方法。
  视图(View):封装的是对数据源Model的一种显示。一个模型能够由多个视图,而一个视图理论上也能够同不一样的模型关联起来。
  控制器(Control):封装的是外界做用于模型的操做。一般,这些操做会转发到模型上,并调用模型中相应的一个或者多个方法。通常Controller在Model和View之间起到了沟通的做用,处理用户在View上的输入,并转发给Model。这样Model和View二者之间能够作到松散耦合,甚至能够彼此不知道对方,而由Controller链接起这两个部分。
  MVC应用程序老是由这三个部分组成。Event(事件)致使Controller改变Model或View,或者同时改变二者。只要Controller改变了Model的数据或者属性,全部依赖的View都会自动更新。相似的,只要Controller改变了View,View会从潜在的Model中获取数据来刷新本身。MVC模式最先是smalltalk语言研究团提出的,应用于用户交互应用程序中。
  在设计模式中,MVC其实是一个比较高层的模式,它由多个更基本的设计模式组合而成,Model-View的关系其实是Observer模式,模型的状态和试图的显示相互响应,而View-Controller则是由Strategy模式所描述的,View用一个特定的Controller的实例来实现一个特定的响应策略,更换不一样的Controller,能够改变View对用户输入的响应。而其它的一些设计模式也很容易组合到这个体系中。好比,经过Composite模式,能够将多个View嵌套组合起来;经过FactoryMethod模式来指定View的Controller,等等。在GOF书的 Introduction中,有一小节是“Design Patterns in Smalltalk MVC”即介绍在MVC模式里用到的设计模式。它大概向咱们传达了这样的信息:合成模式+策略模式+观察者模式约等于MVC模式(固然MVC模式要多一些 东西)。
  使用MVC的好处,一方面,分离数据和其表示,使得添加或者删除一个用户视图变得很容易,甚至能够在程序执行时动态的进行。Model和View可以单独的开发,增长了程序了可维护性,可扩展性,并使测试变得更为容易。另外一方面,将控制逻辑和表现界面分离,容许程序可以在运行时根据工做流、用户习惯或者模型状态来动态选择不一样的用户界面。所以,MVC模式普遍用于Web程序、GUI程序的架构
  这里实现一个Java应用程序。当用户在图形化用户界面输入一个球体的半径时,程序将显示该球体的体积与表面积。咱们首先利用基本MVC模式实现以上程序,而后利用不一样数量的模型、视图、控制器结构来扩展该程序。
  Model与View的交互使用Observer模式。Model类必须继承Observable类,View类必须实现接口Observer。正是因为实现了上述结构,当Model发生改变时(Controller改变Model的状态),Model就会自动刷新与之相关的View。Controller类主要负责新建Model与View,将view与Mode相关联,并处理触发模型值改变的事件。

 1 import java.util.Observable;  
 2   
 3 //Sphere.java:Model类  
 4 //必须继承Observable,在Observable类中,方法addObserver()将视图与模型相关联  
 5 class Sphere extends Observable {  
 6   
 7     private double myRadius;  
 8       
 9     public void setRadius(double r) {  
10         myRadius = r;  
11         this.setChanged();         //指示模型已经改变  
12         this.notifyObservers();    //通知各个视图,从父继承的方法  
13     }  
14     //......  
15 }  
 1 import java.util.Observable;  
 2 import java.util.Observer;  
 3 import javax.swing.JPanel;  
 4   
 5 //TextView.java:View视图类  
 6 //当模型Sphere类的状态发生改变时,与模型相关联的视图中的update()方法  
 7 //就会自动被调用,从而实现视图的自动刷新  
 8 public class TextView extends JPanel implements Observer {  
 9   
10     @Override  
11     public void update(Observable o, Object arg) {  
12         Sphere balloon = (Sphere) o;  
13         radiusIn.setText("" + f3.format(balloon.getRadius()));  
14         volumeOut.setText("" + f3.format(balloon.volume()));  
15         surfAreaOut.setText("" + f3.format(balloon.surfaceArea()));  
16     }  
17     //......  
18 }  
 1 import java.awt.Container;  
 2 import java.awt.event.ActionEvent;  
 3 import javax.swing.JFrame;  
 4 import javax.swing.JTextField;  
 5   
 6 // SphereWindow.java:Controller类  
 7 // 它主要新建Model与View,将view与Mode相关联,并处理事件  
 8 public class SphereWindow extends JFrame {  
 9   
10     public SphereWindow() {  
11         super("Spheres: volume and surface area");  
12         model = new Sphere(0, 0, 100); //新建Model  
13         TextView view = new TextView(); //新建View  
14         model.addObserver(view); //将View与Model相关联  
15         view.update(model, null); //初始化视图,之后就会根据Model的变化自动刷新          
16         view.addActionListener(this);  
17         Container c = getContentPane();  
18         c.add(view);  
19     }  
20   
21     //处理事件:改变Model的状态  
22     public void actionPerformed(ActionEvent e) {  
23         JTextField t = (JTextField) e.getSource();  
24         double r = Double.parseDouble(t.getText());  
25         model.setRadius(r);  
26     }  
27     //......  
28 }  

这种MVC模式的程序具备极其良好的可扩展性。它能够轻松实现一个模型的多个视图;能够采用多个控制器;能够实现当模型改变时,全部视图自动刷新;可使全部的控制器相互独立工做。
  好比实现一个模型、两个视图和一个控制器的程序。当用户在图形化用户界面输入一个球体的半径,程序除显示该球体的体积与表面积外,还将图形化显示该球体。该程序的4个类之间的示意图以下:

 


   图1-2  一个模型、两个视图和一个控制器的基本结构

  

MVC的优势:
  (1)最重要的是应该有多个视图对应一个模型的能力。
在目前用户需求的快速变化下,可能有多种方式访问应用的要求。例如,订单模型可能有本系统的订单,也有网上订单,或者其余系统的订单,但对于订单的处理都是同样,也就是说订单的处理是一致的。按MVC设计模式,一个订单模型以及多个视图便可解决问题。这样减小了代码的复制,即减小了代码的维护量,一旦模型发生改变,也易于维护。 其次,因为模型返回的数据不带任何显示格式,于是这些模型也可直接应用于接口的使用。
  (2)因为一个应用被分离为三层,所以有时改变其中的一层就能知足应用的改变。 一个应用的业务流程或者业务规则的改变只需改动MVC的模型层。
  (3)控制层的概念也颇有效,因为它把不一样的模型和不一样的视图组合在一块儿完成不一样的请求,所以, 控制层能够说是包含了用户请求权限的概念。
   (4)它还有利于软件工程化管理。因为不一样的层各司其职,每一层不一样的应用具备某些相同的特征,有利于经过工程化、工具化产生管理程序代码。
   MVC的不足体如今如下几个方面:   (1)增长了系统结构和实现的复杂性。对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增长结构的复杂性,并可能产生过多的更新操做,下降运行效率。   (2)视图与控制器间的过于紧密的链接。视图与控制器是相互分离,但确实联系紧密的部件,视图没有控制器的存在,其应用是颇有限的,反之亦然,这样就妨碍了他们的独立重用。   (3)视图对模型数据的低效率访问。依据模型操做接口的不一样,视图可能须要屡次调用才能得到足够的显示数据。对未变化数据的没必要要的频繁访问,也将损害操做性能。   (4) 目前,通常高级的界面工具或构造器不支持MVC模式。改造这些工具以适应MVC须要和创建分离的部件的代价是很高的,从而形成使用MVC的困难。
相关文章
相关标签/搜索