Android:四大架构的优缺点,你真的了解吗?

栏目: Android · 发布时间: 6年前

内容简介:你准备好了吗?本次列车开往 “重构” 之巅,时速 900km/s。风太大听不见,但我就是可以很简单很直的,给你讲述事物本质和解决方案!:zap:以下,对常见的 MVC、MVP、Clean、AAC 架构做个比对。首先,一张表格展示各架构的类冗余情况:

你准备好了吗?本次列车开往 “重构” 之巅,时速 900km/s。风太大听不见,但我就是可以很简单很直的,给你讲述事物本质和解决方案!:zap:

项目常用架构比对

以下,对常见的 MVC、MVP、Clean、AAC 架构做个比对。

首先,一张表格展示各架构的类冗余情况:

需求是,写三个页面,ListFragment、DetailFragment、PreviewFragment,每个页面至少用到 3个 Note 业务、3个 User 业务。问:上述架构分别需编写多少类?

Android:四大架构的优缺点,你真的了解吗?

MVC 架构的缺陷

  • View、Controller、Model 相互依赖,造成代码耦合。

  • 难以分工,难以将 View、Controller、Model 分给不同的人写。

  • 难以维护,没有中间件接口做缓冲,难以替换底层的实现。 public class NoteListFragment extends BaseFragment {

    ...

    public void refreshList() { new Thread(new Runnable() { @Override public void run() {

    //view 中直接依赖 model。那么 view 须等 model 编写好才能开工。
    
              mNoteList = mDataManager.getNoteList();
              mHandler.sendMessage(REFRESH_LIST, mNoteList);
          }
      }).start();
    复制代码

    }

    private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg) { case REFRESH_LIST: mAdapter.setList(mNoteList); mAdapter.notifyDataSetChanged(); break; default: } } };

    ... }

MVP 架构的特点与局限

  • MVP 架构的特点是 面向接口编程。在 View、Presenter、Model 之间分别用 中间件接口 做衔接,当有新的底层实现时,能够无缝替换。
  • 此外,MVP 的 View 和 Model 并不产生依赖,因此可以说是对 View 和 Model 做了代码解耦。

public class NoteListContract {

interface INoteListView {

    void showDialog(String msg);

    void showTip(String tip);

    void refreshList(List<NoteBean> beans);
}

interface INoteListPresenter {

    void requestNotes(String type);

    void updateNotes(NoteBean... beans);

    void deleteNotes(NoteBean... beans);
}

interface INoteListModel {

    List<NoteBean> getNoteList();

    int updateNote(NoteBean bean);

    int deleteNote(NoteBean bean);
}
复制代码

}

但 MVP 架构有其局限性。按我的理解,MVP 设计的初衷是, “让天下没有难替换的 View 和 Model” 。该初衷背后所基于的假设是,“上层逻辑稳定,但底层实现更替频繁” 。在这个假设的引导下,使得三者中, 只有 Presenter 具备独立意志和决定权,掌管着 UI 逻辑和业务逻辑,而 View 和 Model 只是外接的工具。

public class NoteListPresenter implements NoteListContract.INoteListPresenter {

private NoteListContract.INoteListModel mDataManager;
private NoteListContract.INoteListView mView;

@Override
public void requestNotes(String type) {
    Observable.create(new ObservableOnSubscribe<List<NoteBean>>() {
        @Override
        public void subscribe(ObservableEmitter<List<NoteBean>> e) throws Exception {
            List<NoteBean> noteBeans = mDataManager.getNoteList();
            e.onNext(noteBeans);
        }
    }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer<List<NoteBean>>() {
                @Override
                public void accept(List<NoteBean> beans) throws Exception {

                    //presenter 直接干预了 UI 在拿到数据后做什么,使得逻辑上没有发生解耦。

                    //正常来说,解耦意味着,presenter 的职能边界仅限返回结果数据,
                    //由 UI 来依据响应码处理 UI 逻辑。

                    mView.refreshList(beans);
                }
            });
}

...
复制代码

}

然而,这样的假设多数时候并不实际。可视化需求是变化多端的,在牵涉到视觉交互时,必然涉及 UI 逻辑的修改,也就是说,View 和 Presenter 的相互牵连,使得 UI 的改动需要 View 和 Presenter 编写者配合着完成,增加沟通协作成本。

长久来看,二者都难以成长。Presenter 编写者容易被各种非本职工作拖累,View 的编写者不会尝试独立自主,例如通过多态等模式将 UI 封装成可适应性的组件,反正 ... 有 Presenter 来各种 if else 嘛。

Clean 架构的特点和不足

Android:四大架构的优缺点,你真的了解吗?

为解决 Presenter 职能边界不明确 的问题,在 Clean 架构中,业务逻辑的职能被转移到领域层,由 Usecase 专职管理。Presenter 则弱化为 ViewModel ,作为代理数据请求,和衔接数据回调的缓冲区。

Clean 架构的特点是 单向依赖、数据驱动编程。 View -> ViewModel -> Usecase -> Model 。

View 对 ViewModel 的单向依赖,是通过 databinding 特性实现的。ViewModel 只负责代理数据请求,在 Usecase 处理完业务返回结果数据时,结果数据被赋值给可观察的 databinding 数据,而 View 则依据数据的变化而变化。

public class NoteListViewModel {

private ObservableList<NoteBean> mListObservable = new ObservableArrayList<>();

private void requestNotes(String type) {
    if (null == mRequestNotesUsecase) {
        mRequestNotesUsecase = new ProveListInitUseCase();
    }

    mUseCaseHandler.execute(mRequestNotesUsecase, new RequestNotesUsecase.RequestValues(type),
            new UseCase.UseCaseCallback<RequestNotesUsecase.ResponseValue>() {
                @Override
                public void onSuccess(RequestNotesUsecase.ResponseValue response) {

                    //viewModel 的可观察数据发生变化后,databinding 会自动更新 UI 展示。

                    mListObservable.clear();
                    mListObservable.addAll(response.getNotes());
                }

                @Override
                public void onError() {

                }
            });
}

...
复制代码

}

但 Clean 架构也有不足:粒度太细 。一个 Usecase 受限于请求参数,因而只能处理一类请求。View 请求的数据包含几种类型,就至少需要准备几个 Usecase。Usecase 是依据当前 View 对数据的需求量身定制的,因此 Usecase 的复用率极低,项目会因而急剧的增加类和重复代码。

Android:四大架构的优缺点,你真的了解吗?

public class RequestNotesUseCase extends UseCase<RequestNotesUseCase.RequestValues, RequestNotesUseCase.ResponseValue> {

private DataManager mDataManager;

@Override
protected void executeUseCase(final RequestValues values) {
    List<NoteBean> noteBeans = mDataManager.getNotes();
    ...
    getUseCaseCallback().onSuccess(new RequestNotesUseCase.ResponseValue(noteBeans));
}

//每新建一个 usecase 类,都需要手动为其配置 请求参数列表 和 响应参数列表。

public static final class RequestValues implements UseCase.RequestValues {
    private String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

public static final class ResponseValue implements UseCase.ResponseValue {

    public List<NoteBean> mBeans;

    public ResponseValue(List<NoteBean> beans) {
        mBeans = beans;
    }
}
复制代码

}

AAC 架构的特点

AAC 也是数据驱动编程。只不过它不依赖于 MVVM 特性,而是直接在 View 中写个观察者回调,以接收结果数据并处理 UI 逻辑。

public class NoteListFragment extends BaseFragment {

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    viewModel.getNote().observe(this, new Observer<NoteBean>() {
        @Override
        public void onChanged(@Nullable NoteBean bean) {
            //update UI
        }
    });
}

...
复制代码

}

你完全可以将其理解为 B/S 架构:从 Web 前端向 Web 后端发送了数据请求,后端在处理完毕后响应结果数据给前端,前端再依据需求处理 UI 逻辑。等于说, AAC 将业务完全压到了 Model 层。

ViaBus 架构的由来及特点

上一轮重构项目在用 Clean 架构,为此我决定跳过 AAC,基于对移动端数据交互的理解,编写“消息驱动编程”架构。

由于借助总线来代理数据的请求和响应,因此取名 ViaBus。

Android:四大架构的优缺点,你真的了解吗?

不同于以往的架构,ViaBus 明确界定了什么是 UI,什么是业务。

UI 的作用是视觉交互,为此 UI 的职责范围是请求数据和处理 UI 逻辑 。业务的作用是供应数据,因此 业务的职责范围是接收请求、处理数据、返回结果数据 。

UI 不需要知道数据是怎么来的、通过谁来的,它只需向 bus 发送一个请求,如果有业务注册了该类 “请求处理者”,那么自然有人来处理。业务也无需知道 UI 在拿到数据后会怎么用,它只需向 bus 回传结果,如果有 UI 注册了“观察响应者”,那么自然有人接收,并依据响应码行事。

这样,在静态 bus 的加持下,UI 和业务是完全解耦的,从根本上解决了相互牵连的问题。此外,不同于上述架构的每个 View 都要对应一个 Presenter 或 ViewModel,在 ViaBus 中,一个模块中的 UI 可以共享多个“业务处理者”实例,使 代码的复用率提升到100%。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

复盘+:把经验转化为能力(第2版)

复盘+:把经验转化为能力(第2版)

邱昭良 / 机械工业出版社 / 39.00

随着环境日趋多变、不确定、复杂、模糊,无论是个人还是组织,都需要更快更有效地进行创新应变、提升能力。复盘作为一种从经验中学习的结构化方法,满足了快速学习的需求,也是有效进行知识萃取与共享的机制。在第1版基础上,《复盘+:把经验转化为能力》(第2版)做了六方面修订: ·提炼复盘的关键词,让大家更精准地理解复盘的精髓; ·基于实际操作经验,梳理、明确了复盘的"底层逻辑"; ·明确了复......一起来看看 《复盘+:把经验转化为能力(第2版)》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具