首先須要清楚的一點是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"。另外歡迎你們關注個人微信公衆號~麼麼麼