Android四大架构的优缺点

简介: Android四大架构的优缺点

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


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


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



image.png

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 架构的特点和不足


image.png

image.png为解决 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 的复用率极低,项目会因而急剧的增加类和重复代码。


image.png

image.png

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 层。



目录
相关文章
|
1月前
|
数据库 Android开发 开发者
构建高性能微服务架构:从理论到实践构建高效Android应用:探究Kotlin协程的优势
【2月更文挑战第16天】 在当今快速迭代和竞争激烈的软件市场中,微服务架构以其灵活性、可扩展性和独立部署能力而受到企业的青睐。本文将深入探讨如何构建一个高性能的微服务系统,涵盖从理论基础到具体实现的各个方面。我们将重点讨论服务拆分策略、通信机制、数据一致性以及性能优化等关键主题,为读者提供一个清晰、实用的指南,以便在复杂多变的业务环境中构建和维护健壮的微服务体系结构。 【2月更文挑战第16天】 在移动开发领域,性能优化和流畅的用户体验是至关重要的。随着技术的不断进步,Kotlin作为一种现代编程语言,在Android开发中被广泛采用,尤其是其协程特性为异步编程带来了革命性的改进。本文旨在深入
241 5
|
4月前
|
SQL 存储 分布式计算
【大数据技术Hadoop+Spark】Hive数据仓库架构、优缺点、数据模型介绍(图文解释 超详细)
【大数据技术Hadoop+Spark】Hive数据仓库架构、优缺点、数据模型介绍(图文解释 超详细)
191 0
|
4月前
|
存储 分布式计算 Hadoop
【大数据技术Hadoop+Spark】HDFS概念、架构、原理、优缺点讲解(超详细必看)
【大数据技术Hadoop+Spark】HDFS概念、架构、原理、优缺点讲解(超详细必看)
119 0
|
3月前
|
存储 监控 微服务
微服务和单体架构是两种不同的软件架构风格,每种都有其自身的优缺点
【1月更文挑战第1天】微服务和单体架构是两种不同的软件架构风格,每种都有其自身的优缺点
52 0
|
2天前
|
传感器 Java Android开发
Android HAL深入探索(1): 架构概述
Android HAL深入探索(1): 架构概述
18 1
|
13天前
|
存储 数据库 Android开发
构建高效安卓应用:采用Jetpack架构组件优化用户体验
【4月更文挑战第12天】 在当今快速发展的数字时代,Android 应用程序的流畅性与响应速度对用户满意度至关重要。为提高应用性能并降低维护成本,开发者需寻求先进的技术解决方案。本文将探讨如何利用 Android Jetpack 中的架构组件 — 如 LiveData、ViewModel 和 Room — 来构建高质量的安卓应用。通过具体实施案例分析,我们将展示这些组件如何协同工作以实现数据持久化、界面与逻辑分离,以及确保数据的即时更新,从而优化用户体验并提升应用的可维护性和可测试性。
|
24天前
|
移动开发 前端开发 数据管理
构建高效Android应用:采用MVVM架构与LiveData的全面指南
在移动开发领域,构建一个既快速又可靠的应用对于开发者来说至关重要。随着Android Jetpack组件的推出,MVVM(Model-View-ViewModel)架构和LiveData已成为实现响应式、可测试且易于维护应用的首选解决方案。本文将深入探讨如何在Android应用中实施MVVM模式,以及如何利用LiveData来优化UI组件的数据更新流程,确保用户界面与业务逻辑之间的高度解耦和流畅交互。
18 4
|
6月前
|
运维 Java Serverless
深度解析四大主流软件架构模型:单体架构、分布式应用、微服务与Serverless的优缺点及场景应用
深度解析四大主流软件架构模型:单体架构、分布式应用、微服务与Serverless的优缺点及场景应用
421 0
|
3月前
|
运维 监控 持续交付
微服务架构的概念、特点、优缺点以及最佳实践
微服务架构的概念、特点、优缺点以及最佳实践
494 1
|
8月前
|
存储 前端开发 安全
【面试题】: bs架构与cs架构的区别以及各自优缺点
bs架构与cs架构的区别以及各自优缺点
1024 0