Android中MVC与MVP框架实例解析

龙旋

共 8716字,需浏览 18分钟

 ·

2021-04-25 12:51

首先先明确一下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通常包含一个或者多个接口协议。


优点:

  • View和 Model之间的耦合度降低,结构清晰,维护方便。

  • 便于单元测试。

  • 代码复用率高,扩展性强。

  • 代码框架更适用于快速迭代开发。


缺点:

  • 类相对较多,如果一个Presenter被多个View引用,那么每个View中都要创建Presenter对象。耦合度提高,为了解决这个问题,后续引入Dagger。


三 MVP的实例(登录实例)


下面会根据这张图进行分析


实现步骤:

  • 创建登录View的接口ILoginView

  • 创建登录Model的接口ILoginModel

  • 创建LoginActivity作为View的实例,实现ILoginView接口

  • 创建LoginModel作为Model的实例,实现ILoginModel接口

  • 创建LoginPresennter文件

  • 效果图


具体实现步骤:


1.创建登录View的接口ILoginView

package showly.com.mytest.view;
        publicinterfaceILoginView{        /*         * 登录时view需要知道是否登录成功后,更新ui         * */ publicvoid isLoginSuccess(boolean success);
}


2.创建登录Model的接口ILoginModel

package showly.com.mytest.model;
        publicinterfaceILoginModel{ /* * 需要判断用户输入的账号与密码是否正确 * */        publicboolean login(String userName,String password); }


3.创建LoginActivity作为View的实例,实现ILoginView接口

publicclassLoginActivityextendsAppCompatActivityimplementsILoginView{
    privateEditText mEtUserName;    privateEditText mMEtPsw;    privateButton mLoginBtn;    privateTextView mTvLoginSuccess; privateLoginPresenter mLoginPresenter;
    @Override    protectedvoid onCreate(Bundle savedInstanceState){        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();        initListener(); }
    privatevoid initListener(){        mLoginPresenter =newLoginPresenter(); mLoginPresenter.setLoginView(this);//将View传递给Presenter层
        mLoginBtn.setOnClickListener(newView.OnClickListener(){            @Override            publicvoid onClick(View view){                //根据用户输入的账号 密码进行登录判断                String userName = mEtUserName.getText().toString();                String psw = mMEtPsw.getText().toString();                mLoginPresenter.login(userName, psw);            }        }); }
    privatevoid 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    publicvoid 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;
public class LoginModel implements ILoginModel{    @Override    publicboolean login(String userName,String password){        /*        * 在这里可以请求服务器或者数据库中的数据        * 请求数据省略,假设请求回来的数据为name:showly password:123456        * */        if(userName.equals("showly")){            if(password.equals("123456")){                returntrue;            }        }        returnfalse;    }}


5.创建LoginPresennter文件

publicclassLoginPresenter{
    /*    * presenter需要持有view与model接口的引用    * */    privateILoginView mILoginView; privateILoginModel mILoginModel;
    //View层中持有presenter的引用,所以可以创建方法从View中传递过来    publicvoid setLoginView(ILoginView loginView){        this.mILoginView = loginView;    }
    //Model层中不持有presenter的引用,所以LoginPresenter构建方法中新建对象    publicLoginPresenter(){        //创建Model对象        mILoginModel =newLoginModel(); }     //presenter持有View与Model,创建方法作为两者的中间站    publicvoid login(String name,String psw){        //将用户输入的用户名 密码传递到Model层进行判断        boolean isSuccess = mILoginModel.login(name, psw);        //将Model层对比数据后的结果返回        mILoginView.isLoginSuccess(isSuccess);    }}


6.效果图


四 开闭原则介绍

在这里介绍一下开闭原则,我们在MVP的实例中看到,我们的View和Model是用接口的形式与Presenter进行关联,有没想过这是为什么呢?

这就涉及到开闭原则了,也就是对扩展进行开放,对修改进行关闭。

举个例子:
我们定义一个接口:

publicinterfaceILoginModel{    publicLoginBean getLoginBean();}


然后创建LoginModel实现这个接口:

publicclassLoginModelimplementsILoginModel{    @Override    publicLoginBean getLoginBean(){      //假设这里用原生系统SQLiteOpenHelper      //查询数据库的代码    }}


此时项目经理说用原生的数据库查询不好,需要换GreenDao进行查询,这个时候我们就需要对getLoginBean方法进行修改,而项目中其它很多地方已经使用了该方法,那我们要怎样才能降低修改的成本呢?


其实我们刚开始设计的时候,就应该考虑到这个问题,根据开闭原则,我们可以让其它地方使用以下的方法进行调用:

publicvoid getData(ILoginModel  loginModel){      loginModel.getLoginBean();  }


这样需要修改的时候,我们可以对修改进行关闭,也就是不修改LoginModel,而是新创建GreenDaoModel,这样就能降低修改的成本。


需要源码的童鞋在公众号【龙旋】对话框输入【MVPDemo】即可获取哦.

浏览 40
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报