1. 问题背景
首先需要清楚的一点是MVP模式的设计初衷是:为了解决在MVC模式中,过于复杂的逻辑和界面之间的交互中Activity的职责不单一的问题,Activity既充当了View层,又充当了Controller层的角色。刨除问题的复杂度,直接谈MVP模式的优越性,都是耍流氓。
这也就是为什么我们很多人,为什么不愿意学习MVP的原因。但是如果遇到了一个比较复杂的问题,MVP的解耦能够让你更加轻松地应对需求的迭代。
本文将一个案例来解释MVP模式的设计方法,但是这里有一个矛盾点:MVP模式本身应该作用于较复杂问题的,但是本文作为入门文章又必须使用一个较简单的场景去设计,这样才能容易看出MVP的结构。
场景描述如下:
APP中有一本书(Model),书本的价格会显示在Activity(View)中,Activity中有两个按钮,可以对书本的价格进行控制(Presenter)。
2. MVP模式的实现
基于上面提出的场景,我们先简单的设计界面:
复制代码
我们设计书本的数据模型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中显示。
Presenter类应该具有涨价/降价的能力,因此我们把Presenter设计成接口更加合理。IPresenter.java
的内容如下:
public interface IPresenter { void increasePrice(); void decreasePrice();}复制代码
再设计一个PresenterImpl
类继承IPresenter
接口,并实现涨价和降价的两个方法。因为需要在Presenter中操作Model,并在View中显示,所以Presenter
需要持有Model和View的对象。Model对象很简单,直接将BookVo
传给Presenter
即可,但是View对象如何处理呢?
我们制定一个IView
接口,向Presenter
暴露我们能够提供的能力,比如这个场景里的显示书籍信息,于是IView
接口内容如下:
public interface IView { void showBookInfo(BookVo vo);}复制代码
我们让MainActivity
实现IView
接口,
@Overridepublic 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()); }}复制代码
现在就可以看到效果了。
3.若干思考
- MVP与MVC有什么区别?有本质区别么?
- 案例中P层和M层为什么要设计成接口?
4. 后续
本文中的Demo源码和思考答案将存在于我的微信公众号中,获取源码(Source)请回复"S2",获取答案(Answer)请回复"A2"。另外欢迎大家关注我的微信公众号~么么么