学习MVP不算久,前段时间才把公司的两个项目完全转换为MVP模式,改了下来,略有心得,给大家分享一下。
才开始学习使用MVP时,看到大家说了很多MVP的优点,代码复用,条理清晰等等。不过我改下来发现,MVP在我看来,最大的优点还是代码解耦,逻辑清晰,至于代码复用,暂时没有感觉很好用,除非是界面和逻辑基本一样的,不然想要复用,其实不太现实。
MVP的优点很明显,缺点其实也很明显,明显项目会多出许多类,增加了项目的复杂程度,而且像某些逻辑及其简单,事件较少的界面,使用MVP实际上反而是累赘,明明用MVC也就几十行代码的事,改成MVP多了好多个类,反而感觉不划算,改需求时又要翻阅好多个类。因此,我建议大家,如果你的某个界面极其简单,其实就不要用MVP了,MVP是逻辑越复杂,优势越明显,逻辑简单时,反而不如MVC好用,希望大家不要为了用MVP而用MVP。
下面来谈谈文章主题,MVP的优化问题,最开始采用网上大家的写法,发现代码的复用性不好,有些逻辑类似的代码,基本上每个presenter 和model都要重新写,于是想到使用Base类的方法,把某些共有的方法抽离以达到代码的复用性,类似于BaseActivity。
举个例子比如网络请求,在MVC中通常是把网络请求封装在BaseActivity中,不过既然是MVP,网络请求自然应该封装在Model里面啦
public abstract class BaseActivityModel implements IPublicModel { //网络连接模式,当一个页面含有多个网络请求时,通过传入不同的模式,选择相应的加载参数 public static final int MODE_ONE=1; public static final int MODE_TWO=2; public static final int MODE_THREE=3; //网络连接工具接口类 protected InternetConnect mConnect; /** * @param mode 请求模式 * @param intent 上个页面传递过来的intent * @param i 请求回调 * @param parameter 请求的一些参数 */ @Override public void requestData (int mode, Intent intent, JsonI i, String... parameter) { HashMap<String, String> map = new HashMap<>(); JsonBean.Payload payload=new JsonBean.Payload(); mConnect.loadParameter(intent,mode,payload,map,parameter);//加载参数,由子类实现 map.put("payload", VolleyConnect.getGson().toJson(payload)); VolleyConnect.getInVolleyConnect().getServiceMsg( map,i);//封装Volley,传入参数以及回调接口 } /** * 设置网络请求 */ @Override public void setMConnect (InternetConnect mConnect) { this.mConnect=mConnect; } }同样的共有的方法和字段抽象出presenter的基类
public abstract class BaseActivityPresenter<T extends IPublicView, E extends IPublicModel> implements IPublicPresenter { protected T view; protected E model; protected RequestResult mRequestResult; protected Handler mHandler; public BaseActivityPresenter (T view) { this.view = view; Type type = getClass().getGenericSuperclass();//使用反射实例化Model Type trueType = ((ParameterizedType) type).getActualTypeArguments()[1]; try { this.model = ((Class<E>) trueType).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } new TimeCount(200, 50, new ITimeCount() { @Override public void isRuning (long millisUntilFinished) { } @Override public void isFinish () { init();//加载子类方法,延时200毫秒加载 } }).start(); } /* 设置网络请求回调 */ public void setRequestResult (RequestResult requestResult) { mRequestResult = requestResult; } /* 获取view的handler,需要传入一个回调接口 */ public void setHandler (IHandler handlerI) { mHandler = view.exposeHandler(handlerI); } @Override public void requestData (final int mode, String... parameter) { view.setLoading(true); model.requestData(mode, view.exposeIntent(), new JsonI() { @Override public void notice (JsonBean bean) { // if (bean.getStatus().equals("0")) { // mRequestResult.requestDataSuccess(mode,bean); // }else{ // mRequestResult.requestDataFail(mode,bean); // } view.setLoading(false); } @Override public void notice (int error) { view.showError(error); } }, parameter); } }
这样我们就可以更加简单方便的使用MVP模式了,下面是使用示例
public class LoginPresenter extends BaseActivityPresenter<ILoginView,LoginModel> implements ILoginPresenter, RequestResult { public LoginPresenter (ILoginView view) { super(view); } @Override public void init () { setRequestResult(this); } @Override public void requestDataSuccess (int mode, JsonBean bean) { } @Override public void requestDataFail (int mode, JsonBean bean) { } }可以看到,LoginPresenter不再需要去写model字段和网络请求逻辑,通过泛型,可以自动创建model,而网络请求,仅仅需要设置对应的回调就可以哒。
总结,这样做进一步降低了代码耦合,方便以后代码维护,而且整个MVP感觉更加简单。