首先先明确一下MVC和MVP到底是设计模式还是框架?
设计模式是从coding层面提炼出来的一种总结,用来使得代码的耦合度达到最大限度的分离,从而可以使你的代码更好的被复用,更容易被替换,更好的拥抱需求的变化。
架构则是着眼于更全局的高度,是保证软件的可用性,可扩展性,可伸缩性,安全等等一系列的指标。
设计模式服务于架构,是实现架构设计的具体手段,架构是从整体上着手设计具有宏观性。
所以说MVC和MVP是一种框架架构模式,不是设计模式。
一 MVC:
是一种经典的三层架构模式,目的是将数据层和视图层分离,使它们的耦合度降低,符合面向对象设计的单一原则。
- M:Model(数据层),实体模型,包含网络请求、数据库读取、文件读取、逻辑运算、业务bean类等等,实际中常用来对数
据的封装和保存。 - V:View(视图层),视图界面,对应于布局文件,更具体的就是视图控件,例如:TextView、ImageView等等。
- C:Controller(控制层),将model数据展示在view上,控制应用程序的流程,业务逻辑的处理;对应于工程宏的
Activity、Fragment、Adapter等。 - 优点:站在Android的角度看个人认为,MVC适用于中小型项目的开发,其开发周期短,效率高,模块职责划分明确。
主要划分层M,V,C三个模块,利于代码的维护。 - 缺点:虽然MVC将数据、视图、控制器划分三层看似层与层之间是耦合度降低了,但是实际开发中并没有起到完全的解耦。因为View对应的XML文件实际能做的事情很少,很多界面显示由Controllor对应的Activity或者Fragment给做了,导致View和Controller之间的分层很模糊,也就是Activity充当Controllor也充当了View,也就造成Activity的职责不清,导致Controllor层非常的臃肿,也进一步导致了耦合度非常的高。
二 MVP:
基于MVC衍生出来的一种模式,将MVC中的C优化成了P,P负责业务核心逻辑,并阻断了View和Model的直接联系,从而使View和Model更加专注自身的逻辑。适合中大型项目。
MVP实际上是使View变薄,View和Model完全解耦。
-
M:和MVC中的M是一样。
-
V:Activity、Fragment,View会包含一个或者多个P的引用用P的逻辑,P也可以控制V的显示。
-
P(Presenter):作为V和M的桥梁,负责从M中拿数据处理后返所以每个P通常包含一个或者多个接口协议。
-
优点:
1.View和 Model之间的耦合度降低,结构清晰,维护方便。
2.便于单元测试。
3.代码复用率高,扩展性强。
4.代码框架更适用于快速迭代开发。 -
缺点:
1.类相对较多,如果一个Presenter被多个View引用,那么每个View中都要创建Presenter对象。耦合度提高,为了解决这个问题,后续引入Dagger。
三 MVP的实例(登录实例)
下面会根据这张图进行分析
步骤:
1.创建登录View的接口ILoginView
2.创建登录Model的接口ILoginModel
3.创建LoginActivity作为View的实例,实现ILoginView接口
4.创建LoginModel作为Model的实例,实现ILoginModel接口
5.创建LoginPresennter文件
6.效果图
具体实现步骤:
1.创建登录View的接口ILoginView
package showly.com.mytest.view;
public interface ILoginView {
/*
* 登录时view需要知道是否登录成功后,更新ui
* */
public void isLoginSuccess(boolean success);
}
2.创建登录Model的接口ILoginModel
package showly.com.mytest.model;
public interface ILoginModel {
/*
* 需要判断用户输入的账号与密码是否正确
* */
public boolean login(String userName, String password);
}
3.创建LoginActivity作为View的实例,实现ILoginView接口
package showly.com.mytest.view;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import showly.com.mytest.R;
import showly.com.mytest.presenter.LoginPresenter;
public class LoginActivity extends AppCompatActivity implements ILoginView {
private EditText mEtUserName;
private EditText mMEtPsw;
private Button mLoginBtn;
private TextView mTvLoginSuccess;
private LoginPresenter mLoginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
}
private void initListener() {
mLoginPresenter = new LoginPresenter();
mLoginPresenter.setLoginView(this);//将View传递给Presenter层
mLoginBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//根据用户输入的账号 密码进行登录判断
String userName = mEtUserName.getText().toString();
String psw = mMEtPsw.getText().toString();
mLoginPresenter.login(userName, psw);
}
});
}
private void initView() {
mEtUserName = (EditText) findViewById(R.id.et_userName);
mMEtPsw = (EditText) findViewById(R.id.et_psw);
mLoginBtn = (Button) findViewById(R.id.btn_login);
mTvLoginSuccess = (TextView) findViewById(R.id.tv_success);
}
@Override
public void isLoginSuccess(boolean success) {
//更新UI
if (success) {
mTvLoginSuccess.setText("登录成功");
mTvLoginSuccess.setTextColor(Color.BLUE);
} else {
mTvLoginSuccess.setText("登录失败");
mTvLoginSuccess.setTextColor(Color.RED);
}
}
}
4.创建LoginModel作为Model的实例,实现ILoginModel接口
package showly.com.mytest.model;
/**
* Created by Administrator on 2018/12/12.
*/
public class LoginModel implements ILoginModel {
@Override
public boolean login(String userName, String password) {
/*
* 在这里可以请求服务器或者数据库中的数据
* 请求数据省略,假设请求回来的数据为name:showly password:123456
* */
if(userName.equals("showly")){
if(password.equals("123456")){
return true;
}
}
return false;
}
}
5.创建LoginPresennter文件
package showly.com.mytest.presenter;
import showly.com.mytest.model.ILoginModel;
import showly.com.mytest.model.LoginModel;
import showly.com.mytest.view.ILoginView;
/**
* Created by Administrator on 2018/12/12.
*/
public class LoginPresenter {
/*
* presenter需要持有view与model接口的引用
* */
private ILoginView mILoginView;
private ILoginModel mILoginModel;
//View层中持有presenter的引用,所以可以创建方法从View中传递过来
public void setLoginView(ILoginView loginView) {
this.mILoginView = loginView;
}
//Model层中不持有presenter的引用,所以LoginPresenter构建方法中新建对象
public LoginPresenter() {
//创建Model对象
mILoginModel = new LoginModel();
}
//presenter持有View与Model,创建方法作为两者的中间站
public void login(String name, String psw) {
//将用户输入的用户名 密码传递到Model层进行判断
boolean isSuccess = mILoginModel.login(name, psw);
//将Model层对比数据后的结果返回
mILoginView.isLoginSuccess(isSuccess);
}
}
6.效果图
四 开闭原则介绍
在这里介绍一下开闭原则,我们在MVP的实例中看到,我们的View和Model是用接口的形式与Presenter进行关联,有没想过这是为什么呢?
这就涉及到开闭原则了,也就是对扩展进行开放,对修改进行关闭。
举个例子:
我们定义一个接口:
public interface ILoginModel {
public LoginBean getLoginBean();
}
然后创建LoginModel实现这个接口:
public class LoginModel implements ILoginModel {
@Override
public LoginBean getLoginBean() {
//假设这里用原生系统SQLiteOpenHelper
//查询数据库的代码
}
}
此时项目经理说用原生的数据库查询不好,需要换GreenDao进行查询,这个时候我们就需要对getLoginBean方法进行修改,而项目中其它很多地方已经使用了该方法,那我们要怎样才能降低修改的成本呢?
其实我们刚开始设计的时候,就应该考虑到这个问题,根据开闭原则,我们可以让其它地方使用以下的方法进行调用:
public void getData(ILoginModel loginModel) {
loginModel.getLoginBean();
}
这样需要修改的时候,我们可以对修改进行关闭,也就是不修改LoginModel,而是新创建GreenDaoModel,这样就能降低修改的成本。
以上属于个人理解,不对的地方请指教。
五 登录Demo代码:公众号回复"MVPDemo"即可获取
小编整理了一份Android电子书籍,需要的童鞋关注底部公众号(longxuanzhigu)回复:“e_books” 即可获取哦!
以下是个人公众号(longxuanzhigu),之后发布的文章会同步到该公众号,方便交流学习Android知识及分享个人爱好文章: