Android架构分析-MVC & MVP

MVC的基本介绍

MVC全称是Model - View - Controller,是模型(model)-视图(view)-控制器(controller)的缩写。MVC是一种框架模式而非设计模式,GOF把MVC看作是3种设计模式:观察者模式、策略模式与组合模式的合体,而核心是观察者模式。简而言之,框架是大智慧,用来对软件设计进行分工;设计模式是小技巧,对具体问题提出解决方案,以提高代码复用率,降低耦合度。

使用 MVC,把业务逻辑抽离到 Controller 中,让 View 层专注于显示 UI。

MVC的优点

(1)首先就是理解比较容易,技术含量不高,这对开发和维护来说成本较低也易于维护与修改。

(2)耦合性不高,表现层与业务层分离各司其职,对开发来说很有利。

MVC的缺点

(1)完全理解MVC并不是很容易。使用MVC需要精心的计划,由于它的内部原理比较复杂,所以需要花费一些时间去思考。同时由于模型和视图要严格的分离,这样也给调试应用程序带来了一定的困难。每个构件在使用之前都需要经过彻底的测试。

(2)对于小项目,MVC反而会带来更大的工作量以及复杂性。

MVC在Android中的应用

Android中对MVC的应用很经典,在Android中视图View层一般采用XML文件进行界面的描述。

而对于模型Model部分则大多对应于本地的数据文件或网络获取的数据体,很多情况下我们对这些数据的处理也会在这一层中进行。

最后的控制器Controller则当之无愧的是右Activity承担。

MVP介绍

在Android中,业务逻辑和数据存取是紧紧耦合的,很多缺乏经验的开发者很可能会将各种各样的业务逻辑塞进某个Activity、Fragment或者自定义View中,这样会使得这些组件的单个类型臃肿不堪。如果不将具体的业务逻辑抽离出来,当UI变化时,你就需要去原来的View中抽离具体业务逻辑,这必然会很麻烦并且易出错。

MVP中把Layout布局和Activity作为View层,增加了Presenter,Presenter层与Model层进行业务的交互,完成后再与View层交互(也就是Activity)进行回调来刷新UI。这样一来,所有业务逻辑的工作都交给了Presenter中进行,使得View层与Model层的耦合度降低,Activity中的工作也进行了简化。但是在实际项目中,随着逻辑的复杂度越来越大,Activity臃肿的缺点仍然体现出来了,因为Activity中还是充满了大量与View层无关的代码,比如各种事件的处理派发,就如MVC中的那样View层和Controller代码耦合在一起无法自拔。

MVP模式是MVC模式的一个演化版本,MVP全称Model-View-Presenter。目前MVP在Android应用开发中越来越重要了。

(1)MVP模式会解除View与Model的耦合,有效的降低View的复杂性。同时又带来了良好的可扩展性、可测试性,保证系统的整洁性和灵活性。

(2)MVP模式可以分离显示层与逻辑层,它们之间通过接口进行通信,降低耦合。理想化的MVP模式可以实现同一份逻辑代码搭配不同的显示界面,因为它们之间并不依赖与具体,而是依赖于抽象。这使得Presenter可以运用于任何实现了View逻辑接口的UI,使之具有更广泛的适用性,保证了灵活度。

MVP模式的三个角色

(1)Presenter – 交互中间人:Presenter主要作为沟通View与Model的桥梁,它从Model层检索数据后,返回给View层,使得View与Model之间没有耦合,也将业务逻辑从View角色上抽离出来。

(2)View – 用户界面:View通常是指Activity、Fragment或者某个View控件,它含有一个Presenter成员变量。通常View需要实现一个逻辑接口,将View上的操作转交给Presenter进行实现,最后,Presenter 调用View逻辑接口将结果返回给View元素。

(3)Model – 数据的存取:Model 角色主要是提供数据的存取功能。Presenter 需要通过Model层存储、获取数据,Model就像一个数据仓库。更直白的说,Model是封装了数据库DAO或者网络获取数据的角色,或者两种数据方式获取的集合。

Android mvc mvp.png

MVP和MVC的对比

MVP架构:

View不直接与Model交互,而是通过与Presenter交互来与Model间接交互。

Presenter与View的交互是通过接口来进行的。

通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑。

MVC架构:

View可以与Model直接交互。

Controller是基于行为的,并且可以被多个View共享。

可以负责决定显示哪个View。

通过一个简单的例子来理解MVP模式

View层:

/**
  * ViewInterface
  * 定义一些通用的view接口
 */
public interface LoadDataView {
    /***
     * 耗时操作,加载数据,显示Progress
     */
    void showLoading();
    /***
     * 隐藏Progress
     */
    void hideLoading();
}

/**
 * 更细小的,用来显示图书细节的View接口
  */
public interface LoadBookView extends LoadDataView {
        void showDetailsView(BookEntity entity);
}

/***
 * Fragment,属于View层,实现了ViewInterface(LoadBookView)
 */
public class BookDetailFragment extends Fragment implements LoadBookView{
    /**图书条形码ISBN号*/
    public static final String ISBN = "9787121060748";
    /**持Presenter对象*/
    private BookDetailsPresenter presenter;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        initWidget();
        presenter = new BookDetailsPresenter(getActivity(), ISBN); // 实例化一个presenter对象
        presenter.setView(this); //让Presenter持一个ViewInterface实例(LoadBookView)
        presenter.loadData(); //告诉Presenter快给我加载Data
    }    

     @Override
    public void showDetailsView(BookEntity entity) {
        //更新UI等操作
    }

    @Override
    public void showLoading() {
        rlProgress.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading() {
        rlProgress.setVisibility(View.GONE);
    }
}

2、Presenter层:

public class BookDetailsPresenter {
    /**持一个Model层的对象,用来从网页接口Rest Api中提取数据*/
    private RestApi restApi = null;
    /**一个ViewInterface对象,用来回调Data给View*/
    private LoadBookView loadBookView;
    private String isbn;

    public BookDetailsPresenter(Context context, String isbn) {
        restApi = new RestApiImpl(context);
        this.isbn =isbn;
    }
    public void setView(LoadBookView loadBookView) {
        this.loadBookView = loadBookView;
    }
    public void loadData() {
        loadBookView.showLoading();
        //耗时操作,开个线程异步的加载数据
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                restApi.getBookDetailByIsbn(isbn, bookDetailsCallback);
            }
        });
        thread.start();
    }
    //匿名内部类,接收bookDetailCallback的回调数据
    private RestApi.BookDetailsCallback bookDetailsCallback = new RestApi.BookDetailsCallback() {
        @Override
        public void onBookEntityLoaded(BookEntity bookEntity) {
            notifyDataLoadedSuccessful(bookEntity);
            BookDetailsPresenter.this.loadBookView.hideLoading();
        }

        @Override
        public void onError(Exception e) {
            //异常后的相关处理
        }
    };

    /***
    * 通知获取数据成功了,赶快通知UI更新吧
    */
    private void notifyDataLoadedSuccessful(final BookEntity bookEntity) {
        Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                BookDetailsPresenter.this.loadBookView.showDetailsView(bookEntity);
            }
        });
    }  
}

3、Model层:

/***
* 整个应用程序需要的数据实体类
*/
public class BookEntity {
    //一些set,get方法
}

/**
 * 一个接口,用来从rest api api获得数据,它的实现在RestApiImpl中
 */
public interface RestApi {
    String API_ISBN_BASE_URL = "https://api.douban.com/v2/book/isbn/";
    /***
    * 更细小的接口,用来将获取到的数据,回调给它的调用者
    */
    interface BookDetailsCallback {
        void onBookEntityLoaded(BookEntity bookEntity);
        void onError(Exception e);
    }
    /**
     * 从网络获取数据,然后通过bookDetailCallback回调给Presenter
     * @param isbn
     * @param bookDetailsCallback
     */
    void getBookDetailByIsbn(final String isbn, final BookDetailsCallback bookDetailsCallback);

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NineDays66

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值