MVP模式三部分
- model(处理业务逻辑)
- view(更新UI界面)
- presenter(连接view与model之间的角色)
其中三者关系如下图所示:
用户仅仅接触到的只是View,而不再是Controller模块。这样当逻辑处理业务过多的时候就不会增加界面类的代码,UI仅仅只做UI更新操作,大家各司其职。
MVP模式实例代码
model类
首先创建一个model的接口,此接口是为了让不同的model去实现这个接口,能储存不同类型的数据,使得成为数据的出入口。
代码如下:public interface MessageModel {void setNumber(Object object);Number getNumber();}实现上述model接口,让具体的model能储存需要用到的数据。
代码如下:public class MyMedol implements MessageModel {private Number number;@Overridepublic void setNumber(Object object) {number = (Number)object;}@Overridepublic Number getNumber() {return number;}}
view类
- 创建一个view的接口,该接口是监听presenter与view之间活动通信,并且触发presenter对UI更新操作。
代码如下:public interface CommonView {void setNewMessage(int id,Object obejct);}
presenter类
- 创建一个presenter类,成为model类与view类之间的通信桥梁。
代码如下:public class MyPresenter {private CommonView commonView;private MyMedol mMedol;private HashMap<String,Integer> map;private Number numberAdd;public MyPresenter(CommonView commonView) {this.commonView = commonView;mMedol = new MyMedol();}public void saveNumber(Number number){mMedol.setNumber(number);}/*** 具体逻辑业务处理*/public void updateUI(){numberAdd = mMedol.getNumber();int first = Integer.parseInt(numberAdd.getFirstNumber());int second = Integer.parseInt(numberAdd.getSecondNumber());//加法numberAdd.setResult(first + second);commonView.setNewMessage(map.get("add"),numberAdd);//乘法Number numberMul = new Number();numberMul.setResult(first * second);commonView.setNewMessage(map.get("mul"),numberMul);//相减Number numberSub = new Number();numberSub.setResult(first - second);commonView.setNewMessage(map.get("sub"),numberSub);}/*** 假如有很多控件需要更新ID,可以通过设置UI需要更新的ID,再判断具体 * 的id去更新数据* @param map*/public void setUIofId(HashMap<String,Integer> map){this.map = map;}}
测试开始
- 首先需要实现CommonView的接口,让当前View与Presenter建立连接。
代码如下:public class MvpActivity extends Activity implements CommonView{private TextView txt_mul,txt_add,txt_sub;private EditText edit_first,edit_second;private Button mButton;private MyPresenter myPresenter;private Number number = new Number();private HashMap<String,Integer> idMap = new HashMap<String,Integer>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_mvp);txt_mul = (TextView)findViewById(R.id.txt_mul);txt_add = (TextView)findViewById(R.id.txt_add);txt_sub = (TextView)findViewById(R.id.txt_sub);edit_first = (EditText)findViewById(R.id.edit_firstNumber);edit_second = (EditText)findViewById(R.id.edit_secondNumber);mButton = (Button)findViewById(R.id.btn_start);//将具体的presenter与当前CommonView绑定,让其相互关联myPresenter = new MyPresenter(this);//储存需要显示的UIidMap.put("mul",R.id.txt_mul);idMap.put("add",R.id.txt_add);idMap.put("sub",R.id.txt_sub);myPresenter.setUIofId(idMap);//设置需要UI更新控件的idmButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {number.setFirstNumber(edit_first.getText().toString());number.setSecondNumber(edit_second.getText().toString());myPresenter.saveNumber(number);myPresenter.updateUI();//点击开始之后就更新UI}});}@Overridepublic void setNewMessage(int id, Object obejct) {Number number = (Number) obejct;Log.i("MvpActivity","id="+R.id.txt_add);switch (id){case R.id.txt_mul:txt_mul.setText(number.getResult()+"");break;case R.id.txt_add:txt_add.setText(number.getResult()+"");break;case R.id.txt_sub:txt_sub.setText(number.getResult()+"");break;}}}
详谈运行过程
- 首先创建的MyPresenter类中就实例化时候就会伴随着生产一个CommonView实例化接口,用于与UI做关系连接
- MyPresenter类中有实例化后的MyMedol对象,再为储存数据创建一个类中的方法,使其在调用方法(saveNumber方法)时候完成数据的储存。
- 在UI中实现CommonView的接口,然后通过myPresenter = new MyPresenter(this)就可以让presenter能与UI沟通并且执行UI更新。
- 假如你UI中涉及需要更新的UI控件很多,你可以像我这样,在presenter中创建一个(setUIofId方法),将所有需要更新的UI控件的id从UI传递到presenter中。再绑定数据与对应控件的id一并返回给UI,在UI(setNewMessage方法)中进行识别。
- 具体调用图解
mvp模式优缺点
优点
- UI(activity)无需进行数据业务处理逻辑,代码之间耦合度降低。
- 代码扩展方便,只需要在对应的presenter中添加新逻辑处理功能即可。
- 减少UI的代码行数,修改UI控件方便。
缺点
- 类文件过多,因为每一个UI就要对应一个Presenter,一个Presenter又至少需要对应一个model,导致类膨胀。
测试代码运行截图
首先添加第一个数字,再填入第二个数字,然后在MyPresenter进行加、减、乘法的逻辑运算,最后显示出来结果。