MVP:你以为我只是游戏中的全场最佳吗?

MVP:你以为我只是游戏中的全场最佳吗?

哈啰,小伙伴们大家好,这里是每天进步一点点的花栗鼠小K

“这不马上要毕业了,前几天和同学聊天,畅想入职之后的工作内容、生活模式等巴拉巴拉一大堆东西。聊到工作,因为大家基本上都是研发嘛,就不可避免地聊到了开发的架构设计模式。当时随便谈论了一下之前学过的框架,无非是 SSM MVC 之类的东西。当时小K心里就留下了一个疑问,这些东西足以支撑自己的工作吗?于是求知欲旺盛的小K就真的去了解一下架构的知识,于是发现了这么一神奇的玩意儿:MVP

怎么,王者之外,还有MVP?我直呼666

MVP:你以为我只是游戏中的全场最佳吗?

我一拍脑袋,今天的分享内容,这不就来了

那就先从是什么聊呗



01


什么是MVP



区别于王者、LOL里的MVP(Most Valuable Player),软件设计中的 MVP 架构是Google开源的一个设计模式,它的人生价值是为了让Code更加优雅清晰的展现出来,它是 ModelViewPresenter 三者的首字母缩写。它的结构简图如下

MVP:你以为我只是游戏中的全场最佳吗?
MVP结构图

View: 是显示数据(model)并且将用户指令(events)传送到presenter以便作用于那些数据的一个接口

Model: 对于Model层也是数据层。它区别于 MVC 架构中的Model,在这里不仅仅只是数据模型。在MVP架构中 Model 它负责对数据的存取操作,例如对数据库的读写,网络的数据的请求等。

Presenter:对于 Presenter 层他是连接 View 层与 Model 层的桥梁并对业务逻辑进行处理。

架构推陈出新、不断演进的终极目的是构筑更好的软件架构,所以才有了 MVCMVP

那么问题来了



02


什么是好的软件架构?



小K私以为好的架构应该满足三点

  1. 软件架构上具有明确的分工,各个模块的功能职责平衡分配,且明确。
  2. 可测试性,通常良好的软件架构都具备良好的可测试性。
  3. 良好的易用性,维护成本低。

可能有小伙伴要发问,为什么从模块分工、可测试性和可用性三个维度进行评价,小K的解释如下

  1. 良好的模块分工,可以大大简化我们对代码的理解难度。虽然通过大量的开发工作,可以训练我们的大脑去分析越来越复杂的逻辑,但是人总有极限,而且简单的逻辑更容易理解、不容易出错,所以,需要遵循单一职责原则,将复杂的业务逻辑分解。
  2. 单元测试可以大大地减少程序运行时才能发现的问题,这通常可以节省「用户反馈」->「Bug修复」->「新版本发布」->「用户安装新版本」这个耗时长达一周以上的过程。所以,程序的可测试性对于程序的稳定性是异常重要的。
  3. 最好的代码是还没被写出来的代码。因此,越少的代码,意味着越少的 bugs。这也意味着尽量以最少的代码实现相同的功能,并非意味着这个开发者懒惰,同时,也不能不看维护成本而盲目赞同一个看似聪明的方案。



03


为什么选择MVP?


先看下传统的 MVC 架构Model View Controller ,我们把业务逻辑放到C层,但是这里会引入另外一个问题,所有的逻辑都在C层,不可避免的会造成C层非常复杂,如果项目越来越大,C层的代码会更加臃肿,维护起来也非常麻烦,而且也没办法简单地做单元测试

MVP:你以为我只是游戏中的全场最佳吗?

现有的 MVC 模式存在以下问题:

视图与控制器间的过于紧密的连接

视图与控制器是相互分离,但却是联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了它们的独立重用。

视图对模型数据的低效率访问

依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。

不太友好的单元测试

特别是App上做单元测试的时候很多东西依赖系统框架,没法脱离用户接口来测试这些逻辑单元。使用MVP对Presenter的测试–不需要使用自动化的测试工具。我们可以在 ModelView 都没有完成时候,就可以通过编写 Mock Object (即实现了 ModelView 的接口,但没有具体的内容的)来测试 Presenter 的逻辑。



03


MVP的优势与缺点



优势
  1. MVP 分离了 View Model 层,Presenter 层充当了桥梁的角色,View 层只负责更新界面即可,这里的View 我们要明白只是一个viewinterface ,它是视图的接口,这样我们在做单元测试的时候可以非常方便编写 Presenter 层代码。关于MVP 的代码测试,我们可以参考 Google 给出的代码,Google 现在也在推行MVP,为此Google发布了一些案例,大家可参考这里android-architecture[1]
  2. 厚重的Controller 层代码也得到了释放,之前我们开发的时候会编写很多的业务逻辑,尽管大家会将Service 层做分离,如Net层,DB层等,但还是无法避免类似的问题,无法重复利用是非常难以忍受的。
  3. 有一点还需要注意,Presenter 是双向绑定的关系,因此,在设计的时候就要注意接口和抽象的使用,尽可能的降低代码的耦合度,这也是 MVP 的宗旨。
缺点

由于对视图的渲染放在了Presenter 中,所以MVPPresenter 的交互会过于频繁。还有一点需要明白,如果Presenter 过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么Presenter 也需要变更了

所以,转向MVP吧!




04


案例



来看一个小Demo,文件结构如图

MVP:你以为我只是游戏中的全场最佳吗?
文件结构图

Callback接口

Callback 接口是Model层给Presenter层反馈请求信息的传递载体,所以需要在Callback中定义数据请求的各种反馈状态:

public interface MvpCallback {
/**
* 数据请求成功
* @param data 请求到的数据
*/

void onSuccess(String data);
/**
* 使用网络API接口请求方式时,虽然已经请求成功但是由
* 于{@code msg}的原因无法正常返回数据。
*/

void onFailure(String msg);
/**
* 请求数据失败,指在请求网络API接口请求方式时,出现无法联网、
* 缺少权限,内存泄露等原因导致无法连接到请求数据源。
*/

void onError();
/**
* 当请求数据结束时,无论请求结果是成功,失败或是抛出异常都会执行此方法给用户做处理,通常做网络
* 请求时可以在此处隐藏“正在加载”的等待控件
*/

void onComplete();
}

Model 类

Model 类中定了具体的网络请求操作。为模拟真实的网络请求,利用postDelayed方法模拟耗时操作,通过判断请求参数反馈不同的请求状态:

public class MvpModel {
/**
* 获取网络接口数据
* @param param 请求参数
* @param callback 数据回调接口
*/

public static void getNetData(final String param, final MvpCallback callback){
// 利用postDelayed方法模拟网络请求数据的耗时操作
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
switch (param){
case "normal":
callback.onSuccess("根据参数"+param+"的请求网络数据成功");
break;
case "failure":
callback.onFailure("请求失败:参数有误");
break;
case "error":
callback.onError();
break;
}
callback.onComplete();
}
},2000);
}
}

View 接口

View接口是Activity与Presenter层的中间层,它的作用是根据具体业务的需要,为Presenter提供调用Activity中具体UI逻辑操作的方法:

public interface MvpView {
/**
* 显示正在加载进度框
*/

void showLoading();
/**
* 隐藏正在加载进度框
*/

void hideLoading();
/**
* 当数据请求成功后,调用此接口显示数据
* @param data 数据源
*/

void showData(String data);
/**
* 当数据请求失败后,调用此接口提示
* @param msg 失败原因
*/

void showFailureMessage(String msg);
/**
* 当数据请求异常,调用此接口提示
*/

void showErrorMessage();
}

Presenter类

Presenter类是具体的逻辑业务处理类,该类为纯Java类,不包含任何Android API,负责请求数据,并对数据请求的反馈进行处理。

Presenter类的构造方法中有一个View接口的参数,是为了能够通过View接口通知Activity进行更新界面等操作。

public class MvpPresenter {
// View接口
private MvpView mView;

public MvpPresenter(MvpView view){
this.mView = view;
}
/**
* 获取网络数据
* @param params 参数
*/

public void getData(String params){
//显示正在加载进度条
mView.showLoading();
// 调用Model请求数据
MvpModel.getNetData(params, new MvpCallback() {
@Override
public void onSuccess(String data) {
//调用view接口显示数据
mView.showData(data);
}
@Override
public void onFailure(String msg) {
//调用view接口提示失败信息
mView.showFailureMessage(msg);
}
@Override
public void onError() {
//调用view接口提示请求异常
mView.showErrorMessage();
}
@Override
public void onComplete() {
// 隐藏正在加载进度条
mView.hideLoading();
}
});
}
}

Activity

在Activity代码中需要强调的是如果想要调用Presenter就要先实现Presenter需要的对应的View接口:

public class MainActivity extends AppCompatActivity implements MvpView  {
//进度条
ProgressDialog progressDialog;
TextView text;
MvpPresenter presenter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView)findViewById(R.id.text);
// 初始化进度条
progressDialog = new ProgressDialog(this);
progressDialog.setCancelable(false);
progressDialog.setMessage("正在加载数据");
//初始化Presenter
presenter = new MvpPresenter(this);
}
// button 点击事件调用方法
public void getData(View view){
presenter.getData("normal");
}
// button 点击事件调用方法
public void getDataForFailure(View view){
presenter.getData("failure");
}
// button 点击事件调用方法
public void getDataForError(View view){
presenter.getData("error");
}
@Override
public void showLoading() {
if (!progressDialog.isShowing()) {
progressDialog.show();
}
}
@Override
public void hideLoading() {
if (progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
@Override
public void showData(String data) {
text.setText(data);
}
@Override
public void showFailureMessage(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
text.setText(msg);
}
@Override
public void showErrorMessage() {
Toast.makeText(this, "网络请求数据出现异常", Toast.LENGTH_SHORT).show();
text.setText("网络请求数据出现异常");
}
}

至此,已经完整地实现了一个简易的MVP架构



05


总结



本篇文章介绍的是架构的一个新玩意MVP,内容相对而言较为浅显,权当是补充课外知识了吧

本期就到这了,下次有栗子,我再来,拜拜~~~

点赞关注不迷路呦

参考资料

[1]

android-architecture: https://link.jianshu.com?t=https%3A%2F%2Fgithub.com%2Fgooglesamples%2Fandroid-architecture


作者    花栗鼠小K

编辑   一口栗子  

原文始发于微信公众号(六只栗子):MVP:你以为我只是游戏中的全场最佳吗?

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/88685.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!