如何一步一步写出MVP架构的代码

把所有代码全部放在Activity里面,是可以实现你想要的任何功能的。但是随着业务越来越复杂,Activity会变得十分臃肿,而且这样的代码也变得毫无可移植性可言。于是我们想到可以把代码来分层。MVP正是一种被广泛认可的分层方案。

分离View

MVP中的V,代表的是View,也就是视图,既然我们所有的代码都在Activity里面,那么我们要做的第一步就是把该留在View层的东西留下,剩下的全部先移到别的地方。

那么问题来了,到底哪些代码是要留在View层的呢?对于一个MVP的新手来说,这个问题暂时不太好回答。

解决问题的关键,在于问恰当的问题。

既然我们暂时不知道这个问题的答案,不如我们先换一个问题来讨论,Activity究竟为我们带来了什么?

  • Activity给我们带来了事件以及事件触发的时机。比如说onCreate,onClick,onDestroy,这些事件的发生是经由Activity告诉我们的,我们在这些事件发生的时候,需要完成相应的业务逻辑,那既然是业务逻辑,我们肯定不能把它们放在View层,而是应该把这个事件传递到下一层,也就是P层。

    public class LoginActivity extends Activity implements LoginInterface {
      private Presenter presenter = new Presenter(this);
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          presenter.onCreate();
      }
    
      public void onClick(View view) {
          presenter.login("User Name", "Password");
      }
    
      @Override
      protected void onDestroy() {
          super.onDestroy();
          presenter.onDestroy();
      }
    }
  • Activity给我们带来了展示输出的方法。用登录界面来举例,我们需要展示“密码不能为空”、“用户名或密码错误”这类的Toast。很明显是视图层的逻辑,所以它们需要被保留在View层。

    public class LoginActivity extends Activity implements LoginInterface {
      @Override
      public void showMessage(String message) {
          Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
      }
    }

    实现的这些接口全部需要P层来主动调用。

  • Activity给我们带来了运行android程序所需要的设备上下文(Context)。当下一层需要用到Context的时候,我们希望Activity实现的接口包含了getContext方法并且返回自己,可以让下一层得到Context。

    public class LoginActivity extends Activity implements LoginInterface {
      @Override
      public Context getContext() {
          return this;
      }
    }

    所有显示的功能都应该留在View层,除此之外,View层还需要封装事件并向P层传递。

    分离P层

    P层是展示层(Presenter),一般来说这里的代码的作用是组织核心功能,比如登陆界面的例子,在用户点击登陆之后,真正登陆的请求发起之前,需要有一些判断,像用户名和密码是否合法,网络是否可用等等。登陆请求返回了之后,根据返回的结果,成功或者失败,来做相应的处理,也是P层所需要完成的任务。

    public class Presenter {
      private final LoginInterface loginInterface;
    
      Presenter(LoginInterface loginInterface) {
          this.loginInterface = loginInterface;
      }
    
      void login(String userName, String password) {
          if (userName.isEmpty() || password.isEmpty()) {
              loginInterface.showMessage("账号密码不能为空");
              return;
          }
          String encryptedPassword = MD5.encrypt(password);
          Account.login(userName, encryptedPassword);
      }
    
      void onLoginSuccess(Message message) {
      }
    
      void onLoginFailure(Message message) {
      }
    }

    分离M层

    M层是模型(Model)层,它主要负责数据的存取。具体的一般都是网络请求、文件读写或者数据库增删改查。举例来说,在登陆的Activity里,User、Account,加密的算法,都是Model的一种。在这个项目中,真正的登陆请求是M层的职责。

    public class MD5 {
      public static String encrypt(String content) {
          return "16FH8KID863HD7210FJD3";
      }
    }
    public class Account {
      public static void login(String userName, String password) {
          // send login request over the internet
      }
    
      public static void logout() {
      }
    }
    public class User {
      public final String name;
      public final String age;
    }

    主动权

    从面向过程的角度来看,代码执行的一般顺序是从View层的某个事件被触发开始,View层不做任何处理,直接将这个事件所需要的数据一并传给Presenter,Presenter的特定事件被触发之后,经过一些分析判断,如果有必要的话,接着向对应的Model层请求数据,Model层经过对数据的增删改查等一系列操作之后,返回Presenter,Presenter再加工一下,最终在View层给用户一些反馈。

    移植

    MVP的结构当中,V层只和P层相互联系,M层也只和P层相互联系。在移植的时候,我们能做的是把一套PM移植到新的V上面,这个V可能是新的Activity,也可能是Fragment,但是你想要分离P层和M层,几乎是不可能的,因为业务是各种各样的,几乎不可能抽象出来。总的来说,MVP的可移植性体现在它能帮助大家很容易的把一套业务移植到新的界面上显示,即分离V与PM,但是很难将P层和M层分开。



文/吴晨(简书作者)
原文链接:http://www.jianshu.com/p/0321f33dff7f
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值