mvc、mvp、mvvm

一、MVC(Model-View-Controller)

MVC是比较直观的架构模式,用户操作->View(负责接收用户的输入操作)->Controller(业务逻辑处理)->Model(数据持久化)->View(将结果反馈给View)。

MVC使用非常广泛,比如JavaEE中的SSH框架(Struts/Spring/Hibernate),Struts(View, STL)-Spring(Controller, Ioc、Spring MVC)-Hibernate(Model, ORM)以及ASP.NET中的ASP.NET MVC框架,xxx.cshtml-xxxcontroller-xxxmodel。(实际上后端开发过程中是v-c-m-c-v,v和m并没有关系,下图仅代表经典的mvc模型)

数据关系
View 接受用户交互请求
View 将请求转交给Controller
Controller 操作Model进行数据更新
数据更新之后,Model通知View更新数据变化
View 更新变化数据

方式:所有方式都是单向通信

使用
MVC中的View是可以直接访问Model的!从而,View里会包含Model信息,不可避免的还要包括一些业务逻辑。在MVC模型里,更关注的Model的不变,而同时有多个对Model的不同显示,及View。所以,在MVC模型里,Model不依赖于View,但是 View是依赖于Model的。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。

二、MVP(Model-View-Presenter)

MVP是把MVC中的Controller换成了Presenter(呈现),目的就是为了完全切断View跟Model之间的联系,由Presenter充当桥梁,做到View-Model之间通信的完全隔离。

.NET程序员熟知的ASP.NET webform、winform基于事件驱动的开发技术就是使用的MVP模式。控件组成的页面充当View,实体数据库操作充当Model,而View和Model之间的控件数据绑定操作则属于Presenter。控件事件的处理可以通过自定义的IView接口实现,而View和IView都将对Presenter负责。

 数据关系
View 接收用户交互请求
View 将请求转交给 Presenter
Presenter 操作Model进行数据更新
Model 通知Presenter数据发生变化
Presenter 更新View数据

MVP的优势
Model与View完全分离,修改互不影响
更高效地使用,因为所有的逻辑交互都发生在一个地方—Presenter内部
一个Preseter可用于多个View,而不需要改变Presenter的逻辑(因为View的变化总是比Model的变化频繁)。
更便于测试。把逻辑放在Presenter中,就可以脱离用户接口来测试逻辑(单元测试)

方式
各部分之间都是双向通信

Presenter处理事件,执行相应的逻辑(UI的逻辑和业务逻辑),这些逻辑映射到Model操作Model。那些处理UI如何工作的代码基本上都位于Presenter。

三、MVVM(Model-View-ViewModel)

如果说MVP是对MVC的进一步改进,那么MVVM则是思想的完全变革。它是将“数据模型数据双向绑定”的思想作为核心,因此在View和Model之间没有联系,通过ViewModel进行交互,而且Model和ViewModel之间的交互是双向的,因此视图的数据的变化会同时修改数据源,而数据源数据的变化也会立即反应到View上。

这方面典型的应用有.NET的WPF,js框架Knockout、AngularJS等。

https://juejin.im/entry/583690d6d20309005fea9fd5

https://juejin.im/collection/5836fca16a22654ac5d16915

MVP模式的流程图如下:


采用MVP模式的优势是:

  1. 把业务逻辑抽离到Presenter层中,View层专注于UI的处理。
  2. 分离视图逻辑与业务逻辑,达到解耦的目的。
  3. 提高代码的阅读性。
  4. Presenter被抽象成接口,可以根据Presenter的实现方式进行单元测试。
  5. 可拓展性强。
在Android上采用MVP模式的优势是:大大优化代码的维护性与拓展性的同时对代码进行深度解耦,使各个层级的分工更加明晰。

用MVP模式实现简单的登录逻辑的方式:

  1. 项目的结构:

从上面的代码结构图可看出,用MVP模式实现登陆模块需要创建6个文件,分别是M、V、P接口文件和接口的对应实现。其中LoginActivity就是View层的具体实现。这样的好处时Activity组件只需要负责处理UI相关逻辑就可以了,而相关的业务逻辑全部抽象到Presenter层中处理。通过这种方式能够很好的避免传统Android开发中的Activity/Fragment等UI组件既负责处理UI逻辑又处理业务逻辑的结果。

. 代码实现

说了这么多,最后我们来看看代码的实现吧。

  1. ILoginModel

    public interface ILoginModel {  
        void login(String name ,String password);  
    }
  2. ILoginPresenter

    public interface ILoginPresenter {  
      
        void loginToServer(String userName,String password);  
      
        void loginSucceed();  
    }
  3. ILoginView

    public interface ILoginView {  
      
        void showProgress(boolean enable);  
      
        void showLoginView();  
    }

上面是登陆模块对应的MVP接口的具体设计,下面我来简单介绍一下接口中的几个方法:

  • ILoginModel.login(String name ,String password)登陆方法,通过该方法向服务器发送登陆请求。
  • ILoginPresenter. loginToServer (String name ,String password)通知Model响应登陆事件。
  • ILoginPresenter. loginSucceed()当登陆事件完成时(成功/失败),Model层要通知该方法登陆事件已完成。
  • ILoginView. showProgress(boolean enable)当Presenter层调用loginToServer (String name ,String password)方法时,要通过该方法通知View层显示加载动画。
  • ILoginView. showLoginView()登陆成功时,Presenter层会通过该方法通知View层登陆已成功。

下面我们来看看这几个接口的具体实现。

  1. LoginModel
    public class LoginModel implements ILoginModel{  
      
        private ILoginPresenter presenter;  
      
        private Handler mHandler = new Handler();  
      
        public LoginModel(ILoginPresenter presenter) {  
            this.presenter = presenter;  
      
        }  
      
        @Override  
        public void login(String name ,String password) {  
            mHandler.postDelayed(new Runnable() {  
                @Override  
                public void run() {  
                    Log.d("LoginModel", "run: ");  
                    presenter.loginSucceed();  
                }  
            },2000);  
        }  
      
    }

上面的Model层实现了login(String name,Stringpassword)登陆方法,该方法的具体实现逻辑是通过线程休眠2秒来模拟网络登陆的过程,登陆成功后会通过LoginPresenter的loginSucceed()方法来通知Presenter层登陆结果。实际开发中我们需要根据具体的业务逻辑来实现该过程。

  1. LoginPresenter
    public class LoginPresenter implements ILoginPresenter{  
      
        private ILoginModel loginModel;  
      
        private ILoginView loginView;  
      
        public LoginPresenter(ILoginView loginView) {  
            this.loginView = loginView;  
            this.loginModel = new LoginModel(this);  
        }  
      
        @Override  
        public void loginToServer(String userName, String password) {  
            loginView.showProgress(true);  
            loginModel.login(userName,password);  
        }  
      
        @Override  
        public void loginSucceed() {  
            loginView.showProgress(false);  
            loginView.showLoginView();  
        }  
    

从上面代码可以看出LoginPresenter的实现逻辑很简单,首先在构造方法中获取ILoginView对象并撞见ILoginModel对象。然后当View层调用loginToServer(String userName, String password)方法成功时,通知View层显示加载动画并调用ILoginModel层的login(String userName, String password)方法向服务器发送登陆请求。当登陆成功后(即Model层通知loginSucceed方法时)通过loginView.showProgress(false)方法通知View层隐藏加载动画,并通知View登陆成功。

  1. LoginActivity
    对于LoginActivity我们只需要关注其中的几个方法即可
    loginBtn.setOnClickListener(new View.OnClickListener() {  
        @Override  
        public void onClick(View v) {  
            //模拟登陆,不需要账号密码  
            loginPresenter.loginToServer("","");  
        }  
    });
@Override  
public void showProgress(boolean enable) {  
    if (enable){  
        progressBar.setVisibility(View.VISIBLE);  
        loginLayout.setVisibility(View.GONE);  
    }else {  
        progressBar.setVisibility(View.GONE);  
        loginLayout.setVisibility(View.VISIBLE);  
    }  
}  
  
@Override  
public void showLoginView() {  
    Toast.makeText(LoginActivity.this,"登陆功",Toast.LENGTHSHORT).show();  
    finish();  
}

上面时实现了ILoginView接口的两个方法。
结合上面的代码可以看出,当点击登陆按钮的监听事件时,我们不需要关注业务逻辑,只需要调用loginPresenter.loginToServer("","");方法即可,然后根据实际情况实现View层中ILoginView接口的方法即可,这样达到了UI业务与逻辑完全分离的目的。













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值