Mvp模式的进一步探索

时间:2021-04-16 09:45:38

对于MVC模式的熟悉以及先入为主的观念造成我对MVP的写法内心深处多少有些抵触,毕竟还是理智的,相信群众的眼镜是雪亮的,大家觉得MVP比MVC好那就是真的好;这不在朋友的帮助下,我也逐渐接受和理解了MVP的一些道道,再加上相信大家对于MVC模式下的代码维护和重构,版本跟新时对繁琐的逻辑感到无比的厌烦吧,那好,今天就将我的一点粗浅的认知说出来请大家指正,大牛请绕行。。。

这里拿一个简单的登录案例来写个例子来看看MVP的影子吧:

就是这样一个简单的布局:
Mvp模式的进一步探索

首先来看Moudle:

public class User {

private String name;
private String password;
private boolean remPsw;
private boolean autoLogin;

//...省略构造方法以及get和set方法
}

然后我们来看一下View和Presenter的Base接口(写Base相信已经是大家一个很好的习惯了,如果你还没有养成这样的习惯建议你…你懂得!)

public interface IBasePresenter {

void start();

}

public interface IBaseView<T> {

void setPresenter(T presenter);
}

这没啥好说的Base接口主要是用来继承的,而这个View接口的 setPresenter方法接受一个Presenter对象作为参数,从方法名不难看出这个方法是给View设置对应的Presenter,具体怎么实现的?等会我们来看看View里面是怎么实现这个方法的…

接下来看一下View和Presenter接口(由 于View和Presenter总是一一对应的关系,所以将他们写在同一接口,这样既方便管理又减少很多命名的繁琐过程)

public interface LoginContract {

interface View extends IBaseView<Presenter>{

void showLoginSuccess();//登录成功的展示或者页面跳转
void showOverLogin();//已经登录过的用户可以跳过登录界面
void showErrorToast();//用户账号和密码输入错误是的Toast提示
User getUserInfo();//获得当前用户对象

}

interface Presenter extends IBasePresenter{

void loginOrNot(User user);//判断用户登录成功

void overLogin();//判断是否略过登录界面

}

}

上述方法已经添加注释这里就不多解释了…

进行下一步,来看看集中逻辑判断代码的Presenter类吧

public class MvpActivityPresenter implements LoginContract.Presenter {

private Context context;
private LoginContract.View view;

public MvpActivityPresenter(Context context, LoginContract.View view) {
this.context = context;
this.view = view;
view.setPresenter(this);
}


@Override
public void overLogin() {
SharedPreferences sharedPreferences = context.getSharedPreferences("user_info", Context.MODE_PRIVATE);
//可以获取用户信息直接传递给下个页面
// String name = sharedPreferences.getString("name", "");
// int age = sharedPreferences.getInt("age", 0);
boolean isLogined=sharedPreferences.getBoolean("islogined",false);
if (isLogined){
view.showOverLogin();
}

}

@Override
public void loginOrNot(User user) {
if (checkAccountAndPassword(user.getName(), user.getPassword())) {
postOrSave(user);//保存数据
view.showLoginSuccess();
}else {
view.showErrorToast();
}

}




/**
* 请求服务器验证账号或者密码是否正确,或进行本地验证
*
* @return
*/

public boolean checkAccountAndPassword(String name, String password) {

if (name.equals("Jack") && password.equals("123456")) {
return true;
}
if ((name == "Jack") && (password == "123456")) {
return true;
}

return false;
}


/**
* 本地保存或者发送给服务器
*/

public void postOrSave(User user) {

SharedPreferences sharedPreferences = context.getSharedPreferences("user_info", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();//获取编辑器
editor.putString("name", user.getName());
editor.putString("password", user.getPassword());
editor.putBoolean("rempassord", user.isRemPsw());
editor.putBoolean("autologin", user.isAutoLogin());
editor.putBoolean("islogined", true);
editor.commit();//提交修改

}

@Override
public void start() {

}
}

注意这里实现的是LoginContract的Presenter接口,所以必须要实现里面所有的方法,后面又添加了保存数据和判断账号密码是否正确的方法,另外注意看里面的两个成员变量:ContextLoginContract的View接口 , 而在构造方法中调用view.setPresenter(this)给View对象设置了当前Prensenter(而后在View中将其实例化…..这里说的对不对,我们在View中见分晓…),所以这个Presenter可以调用LoginContract的View接口里面的方法 , 而View又实现了View接口 , 所以这个Presenter可以在在进行逻辑判断的同时间接与用户交互,也就是说Presenter是通过View接口与View交互的 ,同时在Prenseter中对User进行了操作 , 所以Presenter和Moudle是可以直接交互的 .

好,接下了我们来看一下在MVC中无比强大的View吧:

public class MvpActivity extends AppCompatActivity implements LoginContract.View{

EditText etAccent,etPassword;
CheckBox cbRemPassword,cbAutoLogin;
Button btnLogin ;

private LoginContract.Presenter presenter;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

new MvpActivityPresenter(this,this);
presenter.overLogin();
initView();
getUserData();

}

/**
* 初始化View
*/

private void initView() {
etAccent= (EditText) findViewById(R.id.loginName);
etPassword= (EditText) findViewById(R.id.password);
cbRemPassword= (CheckBox) findViewById(R.id.savePwd);
cbAutoLogin= (CheckBox) findViewById(R.id.openStart);
btnLogin= (Button) findViewById(R.id.btnLogin);
}

/**
* 拿到用户的输入和设置数据
*/

private void getUserData() {

btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {


presenter.loginOrNot(getUser());

}
});


}



@Override
public void setPresenter(LoginContract.Presenter presenter) {
this.presenter=presenter;
}




@Override
public void showLoginSuccess() {
Toast.makeText(MvpActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
//dialog的dismiss
//startActivity(new Intent(MvpActivity.this,...));
}

@Override
public void showOverLogin() {
Toast.makeText(MvpActivity.this, "已登录", Toast.LENGTH_SHORT).show();
}

@Override
public void showErrorToast() {
Toast.makeText(MvpActivity.this, "账号或密码有误", Toast.LENGTH_SHORT).show();
}

@Override
public User getUserInfo() {
String userName=etAccent.getText().toString().trim();
String userPassword=etPassword.getText().toString().trim();
boolean remPassword=cbRemPassword.isChecked();
boolean autoLogin=cbAutoLogin.isChecked();

return new User(userName,userPassword,remPassword,autoLogin);
}


}

仔细看看这个Activity里面的代码,是不是很轻松,里面就做了控件初始化,点击事件的监听和数据的获得等于用户交互的代码;
下面我们来仔细看看这个类,它实现了LoginContract里的View接口,并创建了LoginContract里的Presenter接口对象,并调用接口里面的方法来进行逻辑判断,这样就形成了一个Presenter和View个性独特并且相互合作来完成了登录的实现逻辑;

这就好比有一个逻辑思维严密 , 而性格不张扬低调的理工男—-Presenter爱上了十分漂亮情商特别高的交际花—–View,当二人四目相对,一见钟情,电光石火,然后掏出了各自的爱的秘钥—–Interface , 然后各取所需 , 完美结合 , 你中有我 , 我中有你 , 从此一发不可收拾… !
写出这样一场感人至深,荡气回肠的爱情故事人却不是我们的琼瑶阿姨 , 而是大家的MVP!!!

注: 前面所说的接口笔者指的是手,所有想歪的程序员,到墙角蹲着去………