如上图所示可以看见MVP模式需要具备如下三要素:
View传送指令到Controller,Controller完成业务逻辑后,要求Model改变状态,Model将新的数据发送到View,用户得到反馈。
MVP与MVC对比
这时候你会发现MVC与MVP的结构图都有很大区别,具体区别如下:
MVP架构:
View不直接与Model交互,而是通过与Presenter交互来与Model间接交互。
Presenter与View的交互是通过接口来进行的。
通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑。
MVC架构:
View可以与Model直接交互。
Controller是基于行为的,并且可以被多个View共享。
可以负责决定显示哪个View。
总结
MVC与MVP很相似,但又有很大区别,站在不同分析角度会有不同的观点,这里只是站在基于Android App代码下来分析的结果。
MVP架构的Android应用实战:
完整工程代码点我进入下载页面
背景:如下案例模拟一次用户交互存取数据的过程,用户输入数据后点击保存,然后点击获取数据将保存的数据获取的操作。
UI界面:
工程目录结构:
详细代码:
首先看model层代码,model层提供抽象接口,方便解耦,同时方便测试用例测试model的impl实现代码。如下展示了抽象接口和实现代码。
Model层抽象接口:
public interface IInfoModel { //从数据提供者获取数据方法 InfoBean getInfo(); //存入数据提供者方法 void setInfo(InfoBean info); }Model层抽象实现
public class InfoModelImpl implements IInfoModel { //模拟存储数据 private InfoBean infoBean = new InfoBean(); @Override public InfoBean getInfo() { //模拟存储数据,真实有很多操作 return infoBean; } @Override public void setInfo(InfoBean info) { //模拟存储数据,真实有很多操作 infoBean = info; } }
接着看View层代码,View层同样提供抽象接口,方便解耦,同时方便测试用例测试View的impl实现交互代码。如下展示了抽象接口的代码。
View层的抽象接口:
public interface IInfoView { //给UI显示数据的方法 void setInfo(InfoBean info); //从UI取数据的方法 InfoBean getInfo(); }
public class Presenter { private IInfoModel infoModel; private IInfoView infoView; public Presenter(IInfoView infoView) { this.infoView = infoView; infoModel = new InfoModelImpl(); } //供UI调运 public void saveInfo(InfoBean bean) { infoModel.setInfo(bean); } //供UI调运 public void getInfo() { //通过调用IInfoView的方法来更新显示,设计模式运用 //类似回调监听处理 infoView.setInfo(infoModel.getInfo()); } }
这时候回过头看下View层代码,View层同样实现了View层提供的抽象接口(也就是Activity类,充当UI View)。
如下展示了View层的实现代码:
public class MainActivity extends ActionBarActivity implements IInfoView, View.OnClickListener{ private EditText inputId, inputName, inputAddr; private Button saveBtn, loadBtn; private TextView infoTxt; private Presenter presenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); } private void initData() { presenter = new Presenter(this); inputId = (EditText) findViewById(R.id.id_input); inputName = (EditText) findViewById(R.id.name_input); inputAddr = (EditText) findViewById(R.id.addr_input); saveBtn = (Button) findViewById(R.id.input_confirm); loadBtn = (Button) findViewById(R.id.get_confirm); infoTxt = (TextView) findViewById(R.id.show); saveBtn.setOnClickListener(this); loadBtn.setOnClickListener(this); } @Override public void setInfo(InfoBean info) { StringBuilder builder = new StringBuilder(""); builder.append(info.getId()); builder.append("\n"); builder.append(info.getName()); builder.append("\n"); builder.append(info.getAddress()); infoTxt.setText(builder.toString()); } @Override public InfoBean getInfo() { InfoBean info = new InfoBean(); info.setId(Integer.parseInt(inputId.getText().toString())); info.setName(inputName.getText().toString()); info.setAddress(inputAddr.getText().toString()); return info; } @Override public void onClick(View v) { switch (v.getId()) { case R.id.input_confirm: presenter.saveInfo(getInfo()); break; case R.id.get_confirm: presenter.getInfo(); break; } } }
总结
通过上面的例子可以发现,View(Activity)只负责处理用户交互,并把数据相关的逻辑操作都交给了Presenter去做,而Presenter调用Model处理完数据之后,再通过View的抽象接口更新View显示的信息。这样就实现了完整的解耦UI与逻辑操作。
不过,这种观点也是站在App局部代码的角度来分析看待的,对于小型App完全没这个必要,大型的App和交互复杂的可以考虑这么处理,既可以解耦,还可以方便编写test测试代码。
转自http://blog.csdn.net/yanbober/article/details/45645115