首先须要清楚的一点是MVP模式的设计初衷是:为了解决在MVC模式中,过于复杂的逻辑和界面之间的交互中Activity的职责不单一的问题,Activity既充当了View层,又充当了Controller层的角色。刨除问题的复杂度,直接谈MVP模式的优越性,都是耍流氓。java
这也就是为何咱们不少人,为何不肯意学习MVP的缘由。可是若是遇到了一个比较复杂的问题,MVP的解耦可以让你更加轻松地应对需求的迭代。android
本文将一个案例来解释MVP模式的设计方法,可是这里有一个矛盾点:MVP模式自己应该做用于较复杂问题的,可是本文做为入门文章又必须使用一个较简单的场景去设计,这样才能容易看出MVP的结构。bash
场景描述以下:微信
APP中有一本书(Model),书本的价格会显示在Activity(View)中,Activity中有两个按钮,能够对书本的价格进行控制(Presenter)。app
基于上面提出的场景,咱们先简单的设计界面:ide
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.orzangleli.mvpdemo.MainActivity">
<TextView
android:id="@+id/desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textSize="16dp"
android:gravity="center_vertical"
android:padding="5dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:id="@+id/increase"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="涨价1元"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/decrease"
app:layout_constraintTop_toBottomOf="@id/desc"
android:layout_marginTop="60dp"
/>
<Button
android:id="@+id/decrease"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="降价1元"
app:layout_constraintLeft_toRightOf="@id/increase"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/increase"
/>
</android.support.constraint.ConstraintLayout>
复制代码
咱们设计书本的数据模型BookVo
。学习
public class BookVo {
private String name;
private int price;
private String author;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("BookVo{");
sb.append("name='").append(name).append('\'');
sb.append(", price=").append(price);
sb.append(", author='").append(author).append('\'');
sb.append('}');
return sb.toString();
}
}
复制代码
Activity只负责显示书本的信息,不参与涨价/降价的逻辑处理,因此咱们须要建立一个Presenter类,把价格逻辑交给他处理,处理完以后再在Activity中显示。ui
Presenter类应该具备涨价/降价的能力,所以咱们把Presenter设计成接口更加合理。IPresenter.java
的内容以下:this
public interface IPresenter {
void increasePrice();
void decreasePrice();
}
复制代码
再设计一个PresenterImpl
类继承IPresenter
接口,并实现涨价和降价的两个方法。由于须要在Presenter中操做Model,并在View中显示,因此Presenter
须要持有Model和View的对象。Model对象很简单,直接将BookVo
传给Presenter
便可,可是View对象如何处理呢?spa
咱们制定一个IView
接口,向Presenter
暴露咱们可以提供的能力,好比这个场景里的显示书籍信息,因而IView
接口内容以下:
public interface IView {
void showBookInfo(BookVo vo);
}
复制代码
咱们让MainActivity
实现IView
接口,
@Override
public void showBookInfo(BookVo vo) {
this.mDescTv.setText(vo.toString());
}
复制代码
如今咱们只须要给Presenter添加一个构造方法就行,构造方法中添加两个参数:BookVo和IView对象。PresenterImpl.java
代码以下:
public class PresenterImpl implements IPresenter {
private IView mIView;
private BookVo mBookVo;
public PresenterImpl(IView iView, BookVo vo) {
this.mIView = iView;
this.mBookVo = vo;
}
@Override
public void increasePrice() {
Log.i("lxc", " ---> 涨价了一元");
mBookVo.setPrice(mBookVo.getPrice() + 1);
this.mIView.showBookInfo(mBookVo);
}
@Override
public void decreasePrice() {
Log.i("lxc", " ---> 降价了一元");
mBookVo.setPrice(mBookVo.getPrice() - 1);
this.mIView.showBookInfo(mBookVo);
}
}
复制代码
MainActivity
代码以下:
public class MainActivity extends AppCompatActivity implements IView{
private TextView mDescTv;
private Button mIncreaseBtn, mDecreaseBtn;
private IPresenter mPresenter;
private BookVo vo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initPresenter();
mDescTv = findViewById(R.id.desc);
mIncreaseBtn = findViewById(R.id.increase);
mDecreaseBtn = findViewById(R.id.decrease);
mIncreaseBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.increasePrice();
}
});
mDecreaseBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.decreasePrice();
}
});
mDescTv.setText(vo.toString());
}
private void initData() {
vo = new BookVo();
vo.setName("《百年孤独》");
vo.setAuthor("泰戈尔");
vo.setPrice(100);
}
private void initPresenter() {
mPresenter = new PresenterImpl(this, vo);
}
@Override
public void showBookInfo(BookVo vo) {
this.mDescTv.setText(vo.toString());
}
}
复制代码
如今就能够看到效果了。
- MVP与MVC有什么区别?有本质区别么?
- 案例中P层和M层为何要设计成接口?
本文中的Demo源码和思考答案将存在于个人微信公众号中,获取源码(Source)请回复"S2",获取答案(Answer)请回复"A2"。另外欢迎你们关注个人微信公众号~么么么