了解如何分析一个架构模式
掌握 MVC,MVP,MVVM 架构定义和实现
更多面试内容,面试专题,flutter视频 全套,音视频从0到高手开发。
关注GitHub:https://github.com/xiangjiana/Android-MS
免费获取面试PDF合集
免费提供简历修改建议,获取大厂面试PDF和视频教程android
关于架构的定义,其实在不少书籍和文章中都是不一样的,很难作一个统一。这里列举两个定义: git
在维基百科里是这样定义的:程序员
软件架构是一个系统的草图。软件架构描述的对象是直接构成系统的抽象组件。各个组件之间的链接则明确和相对细致地描述组件之间的通信。在实现阶段,这些抽象组件被细化为实际的组件,好比具体某个类或者对象。 github
在 IEEE 软件工程标准词汇中是这样定义的: 面试
架构是以组件、组件之间的关系、组件与环境之间的关系为内容的某一系统的基本组织结构,以及指导上述内容设计与演化的原理。设计模式
在看过茫茫多的架构定义之后,我理解的架构是这样的:服务器
1.为了解决特定的问题而提出
2.按照特定的原则将系统总体进行模块/组件/角色的划分
3.创建模块/组件/角色间的沟通机制
具体解释一下,首先是要有特定的问题,没有问题空谈架构,仿佛是空中楼阁,没有实用价值,而对应到不一样的问题,会有不一样的解决方式。
其次是模块的划分要根据特定的原则,没有原则随意划分,也就无从去评估一个架构的好坏。最后就是模块间的通讯机制,让系统成为一个总体.网络
最后,架构模式,其实更多的是一种思想,一种规则,每每一种架构模式可能会有不一样的实现方式,而实现方式之间,只有合适与否,并无对错之分。数据结构
上面咱们介绍了架构的定义,根据这个定义,咱们在后面分析架构模式的时候,也会从这三方面进行。架构
知道了架构模式要解决的问题,咱们才能针对性的去看,去想其解决方法是否得当,是否合适。
架构中最重要的就是角色 / 模块的划分,理解了架构模式中的角色划分,才能更好的理解其结构。
角色间的通讯也是重要的。相同的角色划分,采用不一样的通讯方式,每每就构成了不一样的架构模式。
角色间通讯咱们能够理解为数据的流向。在 Android 开发中,通讯中的数据能够理解为两种,一种是数据结构,也就是网络请求,本地存储等通讯使用的 JavaBean,另外一种是事件,也就是控件产生的动做,包括触摸,点击,滑动等等。咱们在通讯过程当中,也主要关注这两种数据。
对于咱们 Android 开发者来讲,常见的架构模式基本上就是 MVC,MVP,MVVM,这三种也是开发 GUI 应用程序常见的模式。
除此以外还有 分层模式,客户端-服务器模式(CS模式),主从模式,管道过滤器模式,事件总线模式 等等。
这篇文章仍是具体分析 MVC,MVP,MVVM 这三种架构模式。
咱们在了解架构的定义之后,可能会想,为何要用这些架构模式呢?在咱们不了解这些模式以前,也是同样的开发。相似设计模式,其实架构模式的目的不是为了让应用软件开发出来,而是让结构更清晰,分工更明确,扩展更方便等等。
咱们能够看看,在不使用架构模式以前咱们是怎么开发的。
举个简单的栗子,咱们界面上有 EditText
,TextView
,Button
三个控件,要实现的功能也比较简单:
1.EditText
接受用户输入的内容
2.处理用户输入的数据
3.数据处理后输出到TextView
中
4.点击Button
清空用户的输入
界面以下:
咱们看看不使用架构模式是怎么开发的,也就是咱们通常经常使用的开发方式:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="10dp" tools:context=".MainActivity"> <TextView android:id="@+id/titleText" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Normal" /> <EditText android:id="@+id/edit" android:layout_width="match_parent" android:layout_height="50dp" android:textColor="@android:color/darker_gray" /> <TextView android:id="@+id/msgText" android:layout_width="wrap_content" android:layout_height="30dp" android:layout_marginTop="10dp" android:text="default msg" android:textColor="@android:color/darker_gray" /> <TextView android:id="@+id/clearText" android:layout_width="match_parent" android:layout_height="30dp" android:layout_marginTop="10dp" android:background="@color/colorPrimary" android:gravity="center" android:text="clear" android:textColor="@android:color/white" /> </LinearLayout>
1.在 Activity / Fragment
中获取 View
,进行事件监听
2.经过 View
事件获取数据后进行处理
3.设置处理后的数据给 View
代码以下:
class NormalFragment : Fragment() { companion object { fun newInstance(): Fragment { return NormalFragment() } } private val handler: Handler = Handler() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.architecture, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) titleText.text = "NORMAL" edit.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(s: Editable?) { handleData(s.toString()) } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } }) clearText.setOnClickListener { edit.setText("") } } // 数据的处理,真实状况下多是网络请求,磁盘存取,大量计算逻辑等等 private fun handleData(data: String) { if (TextUtils.isEmpty(data)) { msgText.text = "default msg" return } msgText.text = "handle data ..." handler.removeCallbacksAndMessages(null) // 延迟来模拟网络或者磁盘操做 handler.postDelayed({ msgText.text = "handled data: $data" }, 3000) } }
默认开发方式的缺点:
咱们来分析一下上面的代码,一个明显的特色就是处理逻辑都集中在了 Activity / Fragment
中,无论是对 View
的操做,仍是对数据的处理。带来的问题就是 Activity / Fragment
中逻辑臃肿,后续扩展牵一发而动全身。并且职责划分不清晰,给后续维护也带来了困难。
既然如此,咱们看看使用架构模式改造后是什么样子的。
其实关于 MVC
架构,在不一样的框架里,实现会有些差异,这也正说明了架构是一种思想。咱们这里选用一种比较主流的实现。
咱们能够看到,上面不使用架构进行开发,带来的问题是 Activity / Fragment 逻辑臃肿,不利于扩展。因此 MVC 就要解决的问题就是:控制逻辑,数据处理逻辑和界面交互耦合。
这里先插一个题外话,其实咱们做为程序员,写代码不只要实现需求,还要让代码易读,易扩展。这一点,每每也能体现功力,并非说使用了各类奇技淫巧才是大神。
不知道你们是否有接触过 Java Swing 桌面应用开发,在 Java Swing 中,界面 / 控件的设置,也是用 Java 代码来实现的,若是不采用架构,最后的结果就是控制逻辑,数据处理以及页面展现的代码都集中在一个类中,读者朋友们能够想象一下,这样的代码简直是难以维护
为了解决上面的问题,MVC
架构里,将逻辑,数据,界面的处理划分为三个部分,模型(Model)-视图(View)-控制器(Controller)。各个部分的功能以下:
Model
模型,负责数据的加载和存储。View
视图,负责界面的展现。Controller
控制器,负责逻辑控制。咱们再看看三者之间是怎么通讯的。
在介绍通讯以前,咱们先解释一下通讯中的数据是什么。其实在 Android 开发中,通讯数据能够理解为两种,一种是数据结构,也就是网络请求,本地存储等通讯使用的 JavaBean
,另外一种是事件,也就是控件产生的动做,包括触摸,点击,滑动等等。咱们在通讯过程当中,也主要关注这两种数据。
在 MVC
架构中,View
产生事件,通知到 Controller
,Controller
中进行一系列逻辑处理,以后通知给 Model
去更新数据,Model
更新数据后,再将数据结构通知给 View 去更新界面。
这就是一个完整 MVC
的数据流向
理解了 MVC
模式,咱们看看其具体实现。
其实在 Android 开发中,其自己默承认以理解为 MVC
结构,把 View
放在 xml
中与 Java
代码解耦,而后 Activity / Fragment
充当 Controller
进行逻辑控制,可是 Android 自己并无对 Model
进行划分,因此每每咱们会让 Activity / Fragment
充当 Model
和 Controller
两个角色。并且每每 xml
中的 View
操做也是在 Activity / Fragment
中,致使有时候 Activity / Fragment
也会充当一些 View
的角色。
因此咱们在具体实现过程当中,要把职责划分清楚,这里咱们让 Fragment
充当 View
的角色,把 Model
和 Controller
的逻辑划分清楚。
咱们先定义三个接口以下:
// 数据模型接口,定义了数据模型的操做 interface IModel { fun setView(view: IView) // 数据模型处理输入的数据 fun handleData(data: String) // 清空数据 fun clearData() } // 视图接口,定义视图的操做 interface IView { fun setController(controller: IController) // 数据处理中状态 fun dataHanding() // 数据处理完成,更新界面 fun onDataHandled(data: String) } // 控制器接口,定义控制器的逻辑 interface IController { fun setModel(model: IModel) // EditText 数据变化,通知控制器 fun onDataChanged(data: String) // 清空按钮点击事件 fun clearData() }
上面三个接口分别定义了 Model,View,Controller
的操做。有一点注意的是,根据 MVC
的通讯流程,View
须要持有 Controller
,Controller
须要持有 Model
,Model
须要持有 View
,因此须要暴露相应的接口。
下面咱们看看具体的实现:
Model 中对数据的处理是添加了 "handled data: "
前缀,并增长了 3 秒的延迟
class HandleModel : IModel { private var view: IView? = null private val handler: Handler = Handler(Looper.getMainLooper()) override fun setView(view: IView) { this.view = view } // 接受到数据后,进行处理,这里设置了 3 秒的延迟,模拟网络请求处理数据的操做 override fun handleData(data: String) { if (TextUtils.isEmpty(data)) { return } view?.dataHanding() handler.removeCallbacksAndMessages(null) // 延迟来模拟网络或者磁盘操做 handler.postDelayed({ // 数据处理完成,通知 View 更新界面 view?.onDataHandled("handled data: $data") }, 3000) } // 接收到清空数据的事件,直接清空数据 override fun clearData() { handler.removeCallbacksAndMessages(null) // 数据清空后,通知 View 更新界面 view?.onDataHandled("") } }
Controller
的实现比较简单,将操做直接转发给 Model
,实际上,对于复杂的业务场景,这里要处理不少业务逻辑。
class HandleController : IController { private var model: IModel? = null override fun onDataChanged(data: String) { model?.handleData(data) } override fun clearData() { model?.clearData() } override fun setModel(model: IModel) { } }
这里 Fragment
充当了 View
的角色,主要负责将 View
的事件传递给 Controller
,以及接受到 Model
的数据进行界面更新。
class MVCFragment : Fragment(), IView { companion object { fun newInstance(): Fragment { return MVCFragment() } } private val model: IModel = HandleModel() private var controller: IController = HandleController() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.architecture, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setController(controller) model.setView(this) titleText.text = "MVC" edit.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(s: Editable?) { // 通知 Controller 输入的数据产生变化 controller?.onDataChanged(s.toString()) } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } }) clearText.setOnClickListener { // 通知 Controller 清空数据事件 controller?.clearData() } } // Model 数据变化,进行界面更新 override fun onDataHandled(data: String) { if (TextUtils.isEmpty(data)) { edit.setText("") msgText.text = "default msg" } else { msgText.text = data } } // Model 数据变化,进行界面更新 override fun dataHanding() { msgText.text = "handle data ..." } override fun setController(controller: IController) { this.controller = controller } }
这样咱们就实现了一个简单的 MVC
结构。
MVC
结构了,通常来讲,Activity / Fragment
会承担 View
和 Controller
两个角色,就会致使 Activity / Fragment
中代码较多View
,View
的修改会致使 Controller
和 Model
都进行改动MVP 要解决的问题和 MVC
大同小异:控制逻辑,数据处理逻辑和界面交互耦合,同时能将 MVC
中的 View
和 Model
解耦。
MVP 架构里,将逻辑,数据,界面的处理划分为三个部分,模型(Model)-视图(View)-控制器(Presenter)。各个部分的功能以下:
Model
模型,负责数据的加载和存储。View
视图,负责界面的展现。Presenter
控制器,负责逻辑控制咱们能够看到,MVP 中的各个角色划分,和 MVC
基本上类似,那么区别在哪里呢?区别就在角色的通讯上。
MVP
和 MVC
最大的不一样,就是 View
和 Model
不相互持有,都经过 Presenter
作中转。View
产生事件,通知给 Presenter
,Presenter
中进行逻辑处理后,通知 Model
更新数据,Model
更新数据后,通知数据结构给 Presenter
,Presenter
再通知 View
更新界面。
这就是一个完整 MVP 的数据流向。
理解了 MVP
以后,咱们看一下其具体实现。
首先咱们定义三个接口:
// 模型接口,定义了数据模型的操做 interface IModel { fun setPresenter(presenter: IPresenter) // 梳理数据 fun handleData(data: String) // 清除数据 fun clearData() } // 视图接口,定义了视图的操做 interface IView { fun setPresenter(presenter: IPresenter) // 数据处理中视图 fun loading() // 数据展现 fun showData(data: String) } // 控制器,定义了逻辑操做 interface IPresenter { fun setView(view: IView) fun setModel(model: IModel) // Model 处理完成数据通知 Presenter fun dataHandled(data: String) // Model 清除数据后通知 Presenter fun dataCleared() // View 中 EditText 文字变化后通知 Presenter fun onTextChanged(text: String) // View 中 Button 点击事件通知 Presenter fun onClearBtnClicked() }
上面定义了 View,Model,Presenter
三个接口,其中 View
和 Model
会持有 Presenter
,Presenter
持有 View
和 Model
。
接着看下接口的实现:
class HandleModel : IModel { private var presenter: IPresenter? = null private var handler = Handler(Looper.getMainLooper()) override fun handleData(data: String) { if (TextUtils.isEmpty(data)) { return } handler.removeCallbacksAndMessages(null) // 延迟来模拟网络或者磁盘操做 handler.postDelayed({ // 数据处理完成,通知 Presenter presenter?.dataHandled("handled data: $data") }, 3000) } override fun clearData() { handler.removeCallbacksAndMessages(null) // 数据清理完成,通知 Presenter presenter?.dataCleared() } override fun setPresenter(presenter: IPresenter) { this.presenter = presenter } }
Model
的实现和前面 MVC
中的实现基本一致,不过在 MVC
中 Model
直接操做 View
进行视图展现,而在 MVP
里,要通知 Presenter
去中转。
这里依旧是 Fragment
充当了 View
的角色,主要负责将 View
的事件传递给 Presenter
,以及接受到 Presenter
的数据进行界面更新。
class MVPFragment : Fragment(), IView { companion object { fun newInstance(): Fragment { val presenter = Presenter() val fragment = MVPFragment() val model = HandleModel() fragment.setPresenter(presenter) model.setPresenter(presenter) presenter.setModel(model) presenter.setView(fragment) return fragment } } var mpresenter: IPresenter? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.architecture, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) titleText.text = "MVP" edit.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(s: Editable?) { // 传递 文字修改 事件给 Presenter mpresenter?.onTextChanged(s.toString()) } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } }) clearText.setOnClickListener { // 传递按钮点击事件给 Presenter mpresenter?.onClearBtnClicked() } } override fun setPresenter(presenter: IPresenter) { this.mpresenter = presenter } // 展现数据处理中的视图 override fun loading() { msgText.text = "handling data ..." } // 展现处理后的数据 override fun showData(data: String) { msgText.text = data } }
这里 Presenter
的实现比较简单,没有太多的业务逻辑,实际应用中,这里会进行业务逻辑的处理。
class Presenter : IPresenter { private var model: IModel? = null private var view: IView? = null override fun setModel(model: IModel) { this.model = model } override fun setView(view: IView) { this.view = view } override fun dataHandled(data: String) { view?.showData(data) } override fun dataCleared() { view?.showData("") } override fun onTextChanged(text: String) { view?.loading() model?.handleData(text) } override fun onClearBtnClicked() { model?.clearData() } }
MVVM
要解决的问题和 MVC
,MVP
大同小异:控制逻辑,数据处理逻辑和界面交互耦合,而且同时能将 MVC
中的 View
和 Model
解耦,还能够把 MVP
中 Presenter
和 View
也解耦。
MVVM
架构里,将逻辑,数据,界面的处理划分为三个部分,模型(Model)-视图(View)-逻辑(ViewModel)。各个部分的功能以下:
Model
模型,负责数据的加载和存储。View
视图,负责界面的展现。ViewModel
控制器,负责逻辑控制。咱们能够看到,MVP
中的各个角色划分,和 MVC
,MVP
基本上类似,区别也是在于角色的通讯上。
咱们上面说到,在 MVP
中,就是 View
和 Model
不相互持有,都经过 Presenter
作中转。这样可使 View
和 Model
解耦。
而在 MVVM
中,解耦作的更完全,ViewModel
也不会持有 View
。其中 ViewModel
中的改动,会自动反馈给 View
进行界面更新,而 View
中的事件,也会自动反馈给 ViewModel
。
要达到这个效果,固然要使用一些工具辅助,比较经常使用的就是 databinding
。
在 MVVM 中,数据的流向是这样的:
View
产生事件,自动通知给 ViewMode
,ViewModel
中进行逻辑处理后,通知 Model
更新数据,Model
更新数据后,通知数据结构给 ViewModel
,ViewModel
自动通知 View
更新界面。
这就是一个完整 MVVM
的数据流向。
MVVM
的实现会复杂一点,咱们先看下接口的定义:
// ViewModel 接口,定义了逻辑操做 interface IViewModel { fun setModel(model: IModel) fun handleText(text: String?) fun clearData() fun dataHandled(data: String?) fun dataCleared() } // 模型接口,定义了数据操做 interface IModel { fun setViewModel(viewModel: IViewModel) fun handleData(data: String?) fun clearData() }
MVVM
中的接口只定义了 ViewModel
和 Model
,没有 View
接口,是由于 View
是经过 databind
和 ViewModel
的。
咱们再看看具体实现:
Model
的实现和上面基本一致,就是对数据的处理,处理完成后通知 ViewModel
。
class HandleModel : IModel { private var viewModel: IViewModel? = null private var handler = Handler(Looper.getMainLooper()) override fun handleData(data: String?) { if (TextUtils.isEmpty(data)) { return } handler.removeCallbacksAndMessages(null) // 延迟来模拟网络或者磁盘操做 handler.postDelayed({ // 数据处理完成通知 ViewModel viewModel?.dataHandled("handled data: $data") }, 3000) } override fun clearData() { handler.removeCallbacksAndMessages(null) // 数据清理完成通知 ViewModel viewModel?.dataCleared() } override fun setViewModel(viewModel: IViewModel) { this.viewModel = viewModel } }
ViewModel
的实现要有些不一样,咱们采用 databind
进行 ViewModel
和 View
的绑定。
其中会定义两个变量,inputText
是和 EditText
双向绑定的数据,handledText
是和 TextView
双向绑定的数据。
当 EditText
中输入的数据有变化,会通知到 inputText
注册的监听器中,而 handledText
值的改变,会自动显示到界面上。
class ViewModel : IViewModel { private var model: IModel? = null // View 绑定的数据,inputText 和 handledText 更新后会自动通知 View 更新界面 var inputText: MutableLiveData<String> = MutableLiveData() var handledText: MutableLiveData<String> = MutableLiveData() init { // 注册数据监听,数据改变后通知 Model 去处理数据 inputText.observeForever { handleText(it) } handledText.value = "default msg" } override fun handleText(text: String?) { if (TextUtils.isEmpty(text)) { handledText.value = "default msg" return } handledText.value = "handle data ..." model?.handleData(text) } // 清空按钮的点击事件绑定 override fun clearData() { model?.clearData() } override fun setModel(model: IModel) { this.model = model model.setViewModel(this) } // Model 数据处理完成,设置 handledText 的值,自动更新到界面 override fun dataHandled(data: String?) { handledText.value = data } // Model 数据处理完成,设置 inputText 的值,自动更新到界面 override fun dataCleared() { inputText.value = "" } }
看一下 View
中的数据绑定。
class MVVMFragment : Fragment() { companion object { fun newInstance(): Fragment { return MVVMFragment() } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { // 使用 databind 进行数据绑定 var binding: ArchitectureBindingBinding = DataBindingUtil.inflate(inflater, R.layout.architecture_binding, container, false) binding.lifecycleOwner = this val viewModel = ViewModel() viewModel.setModel(HandleModel()) binding.viewmodel = viewModel return binding.root } }
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <!--定义 View 中绑定的数据--> <data> <variable name="viewmodel" type="com.zy.architecture.mvvm.ViewModel" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="10dp" tools:context=".MainActivity"> <TextView android:id="@+id/titleText" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="MVVM" /> <!--双向绑定 inputText 到 EditText--> <EditText android:id="@+id/edit" android:layout_width="match_parent" android:layout_height="50dp" android:text="@={viewmodel.inputText}" android:textColor="@android:color/darker_gray" /> <!--绑定 handledText 到 TextView--> <TextView android:id="@+id/msgText" android:layout_width="wrap_content" android:layout_height="30dp" android:layout_marginTop="10dp" android:text="@{viewmodel.handledText}" android:textColor="@android:color/darker_gray" /> <!--绑定清空数据的点击事件 到 TextView--> <TextView android:id="@+id/clearText" android:layout_width="match_parent" android:layout_height="30dp" android:layout_marginTop="10dp" android:background="@color/colorPrimary" android:gravity="center" android:onClick="@{() -> viewmodel.clearData()}" android:text="clear" android:textColor="@android:color/white" /> </LinearLayout> </layout>
经过上面的实现,当 EditText
中文字变化后,会自动修改 inputText
的值,触发 inputText
监听器,此时 ViewModel
将消息传递给 Model
进行处理,Model
数据处理完成后,通知 ViewModel
更新 handledText
的值,自动更新到界面上。
点击清空按钮时,自动调用绑定的点击函数,通知 ViewModel
清空事件,ViewModel
将消息传递给 Model
进行数据清空,Model
数据处理完成后,通知 ViewModel
进行界面更新。
优势:
MVP
的基础上,MVVM
把 View
和 ViewModel
也进行了解耦缺点:
View
和 ViewModel
解耦,致使 Debug 时难以一眼看出 View
的事件传递上面的文章中,咱们介绍了 MVC,MVP,MVVM
三种架构模式,以及其简单的实现。这里咱们再回过头思考一下,何时该使用架构模式呢?
架构模式可使代码模块清晰,职责分工明确,容易扩展,带来的反作用就是会引入大量的接口,致使代码文件数量激增。
咱们在最开始说过,架构模式是用来解决特定的问题的,若是特定的问题在目前阶段不是问题,或者不是主要问题,那么咱们能够先不考虑使用架构模式。好比一个功能很是简单,代码量少,然后续又没有扩展的需求,那咱们直接使用传统方式进行开发,快速且清晰,彻底没有必要为了架构而架构。
对于在开始没有考虑架构模式的代码,后续慢慢去重构,也是一个好的选择。
总结来讲就是:架构虽好,可不要贪杯哦~
更多面试内容,面试专题,flutter视频 全套,音视频从0到高手开发。
关注 GitHub: https://github.com/xiangjiana/Android-MS
免费获取面试PDF合集
免费提供简历修改建议,获取大厂面试PDF