Andori架构高阶面试题——MVC、MVP、MVVM、组件化、模块化解析

MVC

1、Android中MVC是什么?特点?

  1. Model:针对业务模型建立的数据结构和类(与View无关,只与业务相关)
  2. View:XML/JAVA或者JS+HTML进行页面的显示。Activity/Frgament也承担了View的功能。
  3. Controller:Android的控制层通常在Activity、Fragment之中。
    本质就是Controller操作Model层的数据,并且将数据返回给View层展示。

2、Android的MVC的缺点:

  1. Activity并不是MVC中标准的Controller,既有Controller的职责也有View的职责,导致Activity的代码过于臃肿。
  2. View层Model层互相耦合,耦合过重,代码量过大,不易于开发和维护。

MVP

3、Android中的MVP模式

  1. MVP(Model-View-Presenter)
  2. Model:主要提供数据的存储功能。Presenter需要通过Model存取数据。
  3. View: 负责处理点击事件和视图展示(Activity、Fragment或者某个View控件)
  4. PresenterView和Model之间的桥梁,从Model检索数据后返回给View层。使得M/V之间不再有耦合关系。

4、MVP和MVC的区别?(2)

  1. MVP中绝对不允许View直接访问Model
  2. 本质是增加了一个接口降低一层耦合度

5、MVP的特点

  1. Presenter完全将ModelView解耦,主要逻辑处于Presenter中。
  2. Presenter具体View没有直接关联,通过定义好的接口进行交互。
  3. View变更时,可以保持Presenter不变(符合面向对象编程的特点)
  4. View只应该有简单的Set/Get方法、用户输入、界面展示的内容,此外没有更多内容。
  5. 低耦合:Model和View的解耦,决定了该特性。

6、MVP的优点?

  1. 低耦合:Model、View层的变换不会影响到对方。
  2. 可重用性:Model层可以用于多个View。比如请求影视数据,可能有多个页面都需要这个功能,但是Model层代码只要有一份就可以了。
  3. 方便测试:可以单独对Model层和View层进行测试。

7、MVP的缺点

  1. MVP的中使用了接口的方式去连接view层presenter层,如果有一个逻辑很复杂的页面,接口会有很多,导致维护接口的成本非常大。
  2. 解决办法:尽可能将一些通用的接口作为基类,其他的接口去继承。

8、MVP的实现?

Model层

//Model层-数据的实体类:NetInfo.java
public class NetInfo {
    private int code;
    private String msg;
    public NetInfo(int code, String msg){
        this.code = code;
        this.msg = msg;
    }
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
}
//Model层-请求数据时View和Model的交互接口(中间层Presenter去实现):LoadTasksCallBack.java
public interface LoadTasksCallBack<T> {
    void onSuccess(T data);
    void onFailed();
}
//Model层-任务抽象基类【业务接口】: NetTask.java
public interface NetTask<T> {
    void execute(T data, LoadTasksCallBack callBack);
}
/**=============================================
 * Model层核心-具体任务【业务的实际操作】:
 *   1. 实现Model层获取数据的操作.
 * //NetInfoTask.java
 *=============================================*/
public class NetInfoTask implements NetTask<String>{
    @Override
    public void execute(String ip, LoadTasksCallBack callBack) {
        if("192.168.1.1".equals(ip)){
            callBack.onSuccess(new NetInfo(1, "This is a Msg from " + ip));
        }else{
            callBack.onFailed();
        }
    }
}

Presenter层

 * 契约接口:
 *    存放相同业务的Preenter和View-便于查找和维护
 * //NetInfoContract.java
 *=============================================*/
public interface NetInfoContract{
    //1、Presenter定义了获取数据的方法
    interface Presenter{
        void getNetInfo(String ip);
    }
    //2、View中定义了与界面交互的方法
    interface View extends BaseView<Presenter> {
        void setNetInfo(NetInfo netInfo);
        void showError(String msg);
    }
}
/**=========================================
 * Presenter具体实现:NetInfoPresenter.info
 *   1. 分别与View层和Model层Task关联起来(持有了两者的对象)
 *   2. 实现接口getNetInfo()用于View层从Model层获取数据
 *   3. * 次要实现了Task执行中需要的回调接口-代理完成了View与Model的交互(避免了M/V的直接交互)
 *========================================*/
public class NetInfoPresenter implements NetInfoContract.Presenter, LoadTasksCallBack<NetInfo>{
    //1. View层
    private NetInfoContract.View mView;
    //2. Model层任务
    private NetTask mNetTask;
    //3. 分别与View和Model建立关联
    public NetInfoPresenter(NetInfoContract.View view, NetTask netTask){
        mNetTask = netTask;
        mView = view;
    }
    //4. 能让View层获取到Model层数据
    @Override
    public void getNetInfo(String ip) {
        mNetTask.execute(ip, this);
    }
    //5. 实现Model层需要的回调接口-作用是将Model层数据交给View层
    @Override
    public void onSuccess(NetInfo netInfo) {
        mView.setNetInfo(netInfo);
    }
    @Override
    public void onFailed() {
        mView.showError("error");
    }
}

View层

//BaseView.java
//View层的基类:定义了设置Presenter的接口
public interface BaseView<T> {
    void setPresenter(T presenter);
}
//HttpActivity.java
//  View层的具体实现:可以是Activity也可以是Fragment
public class HttpActivity extends Activity implements NetInfoContract.View{
    //1. 中间代理人
    private NetInfoContract.Presenter mPresenter;
    Button mGetButton, mSetButton;
    TextView mTitleTxtView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_activity_http);
        mGetButton = findViewById(R.id.get_fromnet_button);
        mSetButton = findViewById(R.id.set_button);
        mTitleTxtView = findViewById(R.id.title_textview);

        /**==============================================
         *  1、给View层设置Presenter和Model层的Task(获取数据)
         *===============================================*/
        setPresenter(new NetInfoPresenter(this, new NetInfoTask()));

        /**==============================================
         *  2、View层通过Presenter去获取数据
         *===============================================*/
        mGetButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //TODO 从网络请求到数据
                mPresenter.getNetInfo("192.168.1.1");
            }
        });
        mSetButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mTitleTxtView.setText("Local Msg = Hello");
            }
        });
    }

    /**=====================================
     * 3、实现View层的三个接口:设置Presenter和View界面相关功能
     *====================================*/
    @Override
    public void setPresenter(NetInfoContract.Presenter presenter) {
        mPresenter = presenter;
    }
    @Override
    public void setNetInfo(NetInfo netInfo) {
        mTitleTxtView.setText(netInfo.getMsg());
    }
    @Override
    public void showError(String msg) {
        mTitleTxtView.setText(msg);
    }
}

public interface LoginMVPContract{
    //View接口
    public interface ILoginView<T>{
        public void showLoginSuccess(T data);
        public void showLoginFailed(String errorMsg);
    }
    //任务接口
    public interface ILoginTask{
        public void startLogin(String phoneNumber, ILoginCallBack callback);
    }
    //Presenter
    public interface ILoginPresenter{
        public void startLogin(String phoneNumber);
    }
    //Presenter和Task间交互的接口
    public interface ILoginCallBack<T>{
        public void onLoginSuccess(T data);
        public void onLoginFailed(String errorMsg);
    }
}

2、Model的LoginResultBean和LoginTask.java

public class LoginResultBean {
}

public class LoginTask implements LoginMVPContract.ILoginTask{
    @Override
    public void startLogin(String phoneNumber, LoginMVPContract.ILoginCallBack callback) {
        if(true){
            callback.onLoginSuccess(new LoginResultBean());
        }else{
            callback.onLoginFailed("登录失败");
        }
    }
}

3、Presenter

public class LoginPresenter implements LoginMVPContract.ILoginPresenter, LoginMVPContract.ILoginCallBack{

    LoginMVPContract.ILoginView mLoginView;
    LoginMVPContract.ILoginTask mTask;

    public LoginPresenter(LoginMVPContract.ILoginView loginView, LoginMVPContract.ILoginTask task){
        mLoginView = loginView;
        mTask = task;
    }

    /**
     * 接口回调至
     */
    @Override
    public void onLoginSuccess(Object data) {
        mLoginView.showLoginSuccess(data);
    }

    @Override
    public void onLoginFailed(String errorMsg) {
        mLoginView.showLoginFailed(errorMsg);
    }

    @Override
    public void startLogin(String phoneNumber) {
        mTask.startLogin(phoneNumber, this);
    }
}

4、View

public class LoginFragment extends SupportFragment implements LoginMVPContract.ILoginView<LoginResultBean>{

    LoginMVPContract.ILoginPresenter mLoginPresenter;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mLoginPresenter = new LoginPresenter(this, new LoginTask());
        mLoginPresenter.startLogin("17777777777");
    }

    @Override
    public void showLoginSuccess(LoginResultBean data) {
        //登陆成功
    }

    @Override
    public void showLoginFailed(String errorMsg) {
        //登录失败
    }
}

9、怎么优化MVP的类文件量

  1. 采用泛型定义契约类,将model、view、presenter定义在一个契约类中
  2. 结构清晰,一个契约类对应一个业务模块

MVVM

10、MVVM模式的作用和特点?

  1. Model-View-ViewModel,将Presenter替换为ViewModel
  2. ViewModelModel/View进行了双向绑定。
  3. View发生改变时,ViewModel会通知Model进行更新数据
  4. Model数据更新后,ViewModel会通知View更新显示
  5. 谷歌发布了MVVM支持库Data Binding:能将数据绑定到xml
  6. 现在谷歌又推出了ViewModel和LiveData组件用于更方便的实现MVVM

MVVM

模块化和组件化

11、什么是模块化

  1. 一种软件设计技术
  2. 项目的功能拆分为独立可交换的模块
  3. 每个模块都包含执行单独功能必要内容

12、什么是组件化

  1. 组件化软件工程也被成为组件化开发,是一种软件工程的分支。
  2. 强调将一个软件系统拆分为独立的组件(组件可以使模块也可以是web资源等等)

13、模块化和组件化的区别

  1. 两者目的都是重用和解耦
  2. 主要是叫法不同
  3. 模块化侧重于重用,组件化更侧重于业务解耦

14、组件化优点

  1. 组件间可以灵活组建
  2. 一个组件的更改,只要对外提供的接口没有变化,则其他组件不需要再测试。
  3. 缺点:对技术、业务理解度有更高要求。

15、模块化的层次拆分

  1. 基础库
  2. 通用业务层
  3. 应用层

16、模块间通信

  1. 可以自己实现但比较麻烦
  2. 建议用阿里巴巴的开源库。

看完点赞,养成习惯,微信搜一搜「 程序猿养成中心 」关注这个喜欢写干货的程序员。

另外更有Android一线大厂面试完整考点、资料更新在我的Gitee,有面试需要的朋友们可以去参考参考,如果对你有帮助,可以点个Star哦!

Gitee地址:【老陈的Gitee

猜你喜欢

转载自blog.csdn.net/qq_39477770/article/details/108868865