Android-架构和设计模式
Android-架构和设计模式
1. App架构
App 架构的核心思想,主要就是为了降低 UI 逻辑和数据业务逻辑之间的耦合度。
1.1 MVC模式
MVC 即:Model - View - Controller 模式,Model 与 View、View 与 Controller、Controller 与 Model,都是单向直接通信,View 层负责 UI 逻辑,Model 层负责数据,Controller 负责替 View 层操作 Model 层,但由于 Android 中,Activity 通常会同时担任 View 层和 Controller 层,随着业务变得复杂,Activity 也会越来越臃肿,而且 Activity 与 Model 层交互时,相当于 View 层可以与 Model 层直接交互,没有完全解耦。
1.2 MVP模式
MVP 即:Model - View - Presenter 模式,Presenter 与 View、Presenter 与 Model 之间都是双向通信,而 Model 与 View 之间完全没有直接通信,从而彻底解耦。并且由于将 MVC 模式中的 Controller 完全解放成独立的 Presenter,也避免了 Activity 中逻辑代码过多的情况。
MVP 模式的变种:Passive View
Passive View 即:被动 View 层,是 MVP 模式最广泛的一个变种,其核心思想就是:View 层所需的数据,不是由其主动拉取 Presenter 获得的,而是被动地由 Presenter 推送的,在 Android 中,也就是 View 层开放自己被动接受数据的接口,Presenter 在转发 View 层请求数据的逻辑给 Model 后,由 Model 通过 Presenter 来主动调用 View 的接口来回传数据。
1.3 MVVM模式
MVVM 即:Model - View - ViewModel 模式,View 仍然对应了 UI 层,Model 仍然是负责主要的数据处理,但一些和 View 层有关的属性及操作则放入了 ViewModel 中实现,其关键在于 DataBinding 技术,View 的变化和 ViewModel 的操作会双向同步,实际上是 Jetpack 框架替开发人员做了一些工作。
DataBinding 原理
DataBinding 会对布局文件中使用
<layout>
标签包裹的元素预处理,会为每个元素增加一个tag
属性,然后将各个元素抽取出来生成一个名为xxxxx-layout.xml
的文件(xxxxx
是原本 xml 布局文件的命名),文件中将原本的所有 View 标签,都转换成了<Target id="xxx" tag="yyy" view="ZzzView">
的形式,其中根布局对应的 tag 是layout
,然后根据原布局文件和新生成的文件,生成一个继承自ViewDataBinding
的类,并将布局文件中的元素,都根据类型和 id 创建成员变量。
2. 设计模式
2.1 单例模式
2.1.1 饿汉式
饿汉式写法简单,线程安全,但没有懒加载的效果,如果没有使用过会浪费内存
1 | public class Singleton { |
2.1.2 懒汉式
懒汉式:懒加载,节约内存,但线程不安全
1 | public class Singleton { |
2.1.3 线程安全的懒汉式
线程安全的懒汉式:懒加载同时线程安全,但使用锁会造成不必要的同步开销,大部分情况下用不到同步
1 | public class Singleton { |
2.1.4 双锁检测DCL
双锁检测:懒加载,线程安全,效率高,但 volatile 影响一点性能,高并发下有一定的缺陷。volatile 关键字可以禁止代码重排序,所有的写(write)操作都将发生在读(read)操作之前,保证singleton是一定被初始化了的。
1 | public class Singleton { |
2.1.5 静态内部类
静态内部类:懒加载,线程安全,推荐使用
1 | public class Singleton { |
2.2 工厂模式
2.2.1 简单工厂模式
(1)定义抽象产品类及公共接口
1 | public abstract class Product { |
(2)定义具体产品类
1 | public class ProductA extends Product { |
(3)创建工厂类,创建具体的产品
1 | public class Factory { |
2.2.2 抽象工厂模式
抽象工厂最复杂,假如有 N
种产品,M
个工厂实体,则一共会有 N * M
种产品实体。
(1)创建抽象产品类
1 | public abstract class CPU { |
(2)创建产品实体类
1 | public class IntelCPU extends CPU { |
(3)创建抽象工厂类
1 | public abstract class ComputerFactory { |
(4)创建工厂实体类
1 | public class DellComputerFactory extends ComputerFactory { |
2.2.3 工厂方法模式
工厂方法模式可以看成是抽象工厂模式的一个特例,当抽象工厂中,只有一种产品时,就和工厂方法一样了。
(1)创建抽象产品类
1 | public abstract class Product { |
(2)创建产品实体类
1 | public class ProductA extends Product { |
(3)创建抽象工厂类
1 | public abstract class Factory { |
(4)创建工厂实体类
1 | public class FactoryA extends Factory { |
2.3 建造者模式
(1)创建产品实体类
1 | public class Computer { |
(2)创建建造者抽象类
1 | public abstract class Builder { |
(3)创建建造者实体类
1 | public class ConcreteBuilder extends Builder { |
(4)创建指挥者实体类,用于控制建造者进行建造任务
1 | public class Director { |
2.4 观察者模式
java.util.Observable
:抽象被观察者。
- 需要继承并根据不同功能重写
Observable
,表示被观察者。使用单例模式,由静态内部类管理一个实例,将构造方法私有化。 Observable
的实例(单例)对象也就是被观察者,在内部根据需要添加方法,方法内部调用setChanged()
和notifyObservers(Object data)
。- 而被观察者需要通过调用
Observable#addObserver(Object observer)
来添加观察者。 notifyObservers(Object data)
方法内部会遍历所有添加给被观察者的观察者,并调用观察者的update(Observable observable, Object arg)
方法,也即表示带着数据data
通知所有观察者。- 因此充当观察者的类(添加给被观察者的类)需要实现
Observe
接口,重写update(Observable o, Object arg)
方法,用instanceof
判断参数observable
到底是哪一个被观察者,然后用数据arg
做相应的操作。
(1)一个被观察者可以被多个观察者观察,也即给被观察者 add
多个观察者,并添加业务方法,当业务执行的时候,业务方法内部会通知所有被添加的观察者,所有被添加的观察者都会收到通知,但一个被观察者可以有多个业务,并不是每个观察者都需要用到每个业务,因此可以在不同业务的方法内的 notifyObservers(Object data)
中,传不同类型的数据 data
,在观察者的 update(Observable observable, Object arg)
方法内,需要用 instanceof
判断数据 arg
的类型,来判断自己是否需要处理。
(2)一个观察者可以观察多个被观察者,也就是多个被观察者调用 Observable.addObserver()
的时候,可以添加同一个观察者,因此当观察者的 update(Observable observable, Object arg)
方法被调用时,还要先用 instanceof
来判断参数 observable
到底是来自哪个被观察者,然后再用 instanceof
判断数据 arg
是由被观察者中哪个业务方法调用传递过来的,这样才能唯一确定一个业务逻辑。
(3)接口回调与观察者模式的选择:回调是一对一的关系,只监听一个事件;观察者模式则是可以一对多也可以多对一,因此观察者模式的数据流图是网状结构,如果业务逻辑比较简单的时候,用回调反而能提升代码可读性以及降低开发复杂度。
2.5 中介者模式
当程序存在大量的类时,多个对象之间存在着依赖的关系,呈现出网状结构,那么程序的可读性和可维护性就变差了,并且修改一个类需要牵涉到其他类,不符合开闭原则。
当多个类之间有复杂交互时,通过创建一个中介者类,用于处理其他类之间的交互问题,提高耦合但也提高了代码逻辑清晰度和可读性,在类和类交互时,也不需要针对不同的类定制专用的接口,只需要通过中介者提供的公用接口调用即可。