目录
1.1 MVC(Model-View-Controller)
1.3 MVVM(Model-View-ViewModel)
1. MVC MVP MVVM 间的区别
三者的区别如下图所示:
1.1 MVC(Model-View-Controller)
- Model:代表我们的数据模型,管理数据状态。
- View:视图,即呈现给用户的UI,比如我们的layout.xml文件及Activity。
- Controller:控制者,负责处理用户与app之间的交互,包含业务逻辑。所以是Model与View的中介,比如我们的Activity/Fragment。
缺点:如上图所示,View与Model之间还存在依赖关系,Controller很‘重’很复杂。在Android中Activity即是View又是Controller,所以会很复杂。
1.2 MVP(Model-View-Presenter)
- Model:代表我们的数据模型,管理数据状态。
- View:视图,即呈现给用户的UI,并且负责与客户进行交互。比如我们的XML/Activity/Fragment。
- Presenter:主持者,Presenter通过View接收用户的输入,然后在Model的帮助下处理用户的数据并将结果传递回View。Presenter通过接口与View进行通信。接口在presenter类中定义,它传递所需的数据。Activity/Fragment 及其他View视图组件实现此接口获得他们想要的数据并呈现数据。
优点:将View与Model解耦,方便进行单元测试。
缺点:虽然是MVC模式的演变,但Presenter依旧很‘重’很复杂。
1.3 MVVM(Model-View-ViewModel)
- Model:代表我们的数据模型,管理数据状态。
- View:视图,即呈现给用户的UI,并且负责与客户进行交互。比如我们的XML/Activity/Fragment。
- ViewModel:如上图所示,ViewModel与Presenter的区别,在MVVM中,View引用持有ViewModel,但ViewModel得不到任何关于View的信息。所以View与ViewModel之间存在着一对多的关系,一个View可以持有多个ViewModel
是MVP模式的一个优化。
2. 例子Demo
分别用MVC MVP MVVM设计模式来实现一个用户登入的功能:如下:
![](https://i-blog.csdnimg.cn/blog_migrate/e9c69e320acd8af75eb8d4d0f8ccc7d5.gif)
2.1 MVC
Controller层:
public class MvcLoginActivity extends AppCompatActivity {
private EditText userNameEt;
private EditText passwordEt;
private User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvc_login);
user = new User();
userNameEt = findViewById(R.id.user_name_et);
passwordEt = findViewById(R.id.password_et);
Button loginBtn = findViewById(R.id.login_btn);
loginBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
login(userNameEt.getText().toString(), passwordEt.getText().toString());
}
});
}
private void login(String userName, String password) {
if (userName.equals("jere") && password.equals("123")) {
user.setUserName(userName);
user.setPassword(password);
Toast.makeText(MvcLoginActivity.this,
userName + " Login Successful",
Toast.LENGTH_SHORT)
.show();
} else {
Toast.makeText(MvcLoginActivity.this,
"Login Failed",
Toast.LENGTH_SHORT)
.show();
}
}
}
2.2 MVP
Model层:
public interface IUserBiz {
boolean login(String userName, String password);
}
/**
* User业务逻辑实现
*/
public class UserBiz implements IUserBiz {
@Override
public boolean login(String userName, String password) {
if (userName.equals("jere") && password.equals("123")) {
User user = new User();
user.setUserName(userName);
user.setPassword(password);
return true;
}
return false;
}
}
Presenter层:
public class LoginPresenter{
private UserBiz userBiz;
private IMvpLoginView iMvpLoginView;
public LoginPresenter(IMvpLoginView iMvpLoginView) {
this.iMvpLoginView = iMvpLoginView;
this.userBiz = new UserBiz();
}
public void login() {
String userName = iMvpLoginView.getUserName();
String password = iMvpLoginView.getPassword();
boolean isLoginSuccessful = userBiz.login(userName, password);
iMvpLoginView.onLoginResult(isLoginSuccessful);
}
}
View层:
public interface IMvpLoginView {
String getUserName();
String getPassword();
void onLoginResult(Boolean isLoginSuccess);
}
public class MvpLoginActivity extends AppCompatActivity implements IMvpLoginView{
private EditText userNameEt;
private EditText passwordEt;
private LoginPresenter loginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp_login);
userNameEt = findViewById(R.id.user_name_et);
passwordEt = findViewById(R.id.password_et);
Button loginBtn = findViewById(R.id.login_btn);
loginPresenter = new LoginPresenter(this);
loginBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
loginPresenter.login();
}
});
}
@Override
public String getUserName() {
return userNameEt.getText().toString();
}
@Override
public String getPassword() {
return passwordEt.getText().toString();
}
@Override
public void onLoginResult(Boolean isLoginSuccess) {
if (isLoginSuccess) {
Toast.makeText(MvpLoginActivity.this,
getUserName() + " Login Successful",
Toast.LENGTH_SHORT)
.show();
} else {
Toast.makeText(MvpLoginActivity.this,
"Login Failed",
Toast.LENGTH_SHORT).show();
}
}
}
2.3 MVVM
ViewModel层:
public class LoginViewModel extends ViewModel {
private User user;
private MutableLiveData<Boolean> isLoginSuccessfulLD;
public LoginViewModel() {
this.isLoginSuccessfulLD = new MutableLiveData<>();
user = new User();
}
public MutableLiveData<Boolean> getIsLoginSuccessfulLD() {
return isLoginSuccessfulLD;
}
public void setIsLoginSuccessfulLD(boolean isLoginSuccessful) {
isLoginSuccessfulLD.postValue(isLoginSuccessful);
}
public void login(String userName, String password) {
if (userName.equals("jere") && password.equals("123")) {
user.setUserName(userName);
user.setPassword(password);
setIsLoginSuccessfulLD(true);
} else {
setIsLoginSuccessfulLD(false);
}
}
public String getUserName() {
return user.getUserName();
}
}
View层:
public class MvvmLoginActivity extends AppCompatActivity {
private LoginViewModel loginVM;
private EditText userNameEt;
private EditText passwordEt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvvm_login);
userNameEt = findViewById(R.id.user_name_et);
passwordEt = findViewById(R.id.password_et);
Button loginBtn = findViewById(R.id.login_btn);
loginBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
loginVM.login(userNameEt.getText().toString(), passwordEt.getText().toString());
}
});
loginVM = ViewModelProviders.of(this).get(LoginViewModel.class);
loginVM.getIsLoginSuccessfulLD().observe(this, loginObserver);
}
private Observer<Boolean> loginObserver = new Observer<Boolean>() {
@Override
public void onChanged(@Nullable Boolean isLoginSuccessFul) {
if (isLoginSuccessFul) {
Toast.makeText(MvvmLoginActivity.this,
loginVM.getUserName() + " Login Successful",
Toast.LENGTH_SHORT)
.show();
} else {
Toast.makeText(MvvmLoginActivity.this,
"Login Failed",
Toast.LENGTH_SHORT)
.show();
}
}
};
}
参考文献: