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
2
3
4
5
public class Singleton {
private Singleton() {}
private static final Singleton singleton = new Singleton();
pubilc static Singleton getInstance() { return singleton; }
}

2.1.2 懒汉式

懒汉式:懒加载,节约内存,但线程不安全

1
2
3
4
5
6
7
8
9
10
public class Singleton {
private Singleton() {}
private stati Singleton singleton = null;
pubilc static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}

2.1.3 线程安全的懒汉式

线程安全的懒汉式:懒加载同时线程安全,但使用锁会造成不必要的同步开销,大部分情况下用不到同步

1
2
3
4
5
6
7
8
9
10
public class Singleton {
private Singleton() {}
private stati Singleton singleton = null;
pubilc static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}

2.1.4 双锁检测DCL

双锁检测:懒加载,线程安全,效率高,但 volatile 影响一点性能,高并发下有一定的缺陷。volatile 关键字可以禁止代码重排序,所有的写(write)操作都将发生在读(read)操作之前,保证singleton是一定被初始化了的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
private volatile static Singleton singleton;
private Singleton() { }
public Singleton getInstance() {
if (null == singleton) {
synchronized (Singleton.class) {
if (null == singleton) {
singleton = new Singleton();
}
}
}
return singleton;
}
}

2.1.5 静态内部类

静态内部类:懒加载,线程安全,推荐使用

1
2
3
4
5
6
7
8
9
10
11
public class Singleton {
private Singleton() { }
public static Singleton getInstance() {
//第一次调用getInstance方法时才加载SingletonHolder并初始化sInstance
return SingletonHolder.sInstance;
}
//静态内部类
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}

2.2 工厂模式

2.2.1 简单工厂模式

(1)定义抽象产品类及公共接口

1
2
3
public abstract class Product {
public abstract void show();
}

(2)定义具体产品类

1
2
3
4
5
6
7
8
9
10
11
12
public class ProductA extends Product {
@Override
public void show() {
System.out.println("product A");
}
}
public class ProductB extends Product {
@Override
public void show() {
System.out.println("product B");
}
}

(3)创建工厂类,创建具体的产品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Factory {
public static Product create(String productName) {
Product product = null;
switch (productName) {
case "A":
product = new ProductA();
break;
case "B":
product = new ProductB();
break;
}
return product;
}
}

2.2.2 抽象工厂模式

抽象工厂最复杂,假如有 N 种产品,M 个工厂实体,则一共会有 N * M 种产品实体。

(1)创建抽象产品类

1
2
3
4
5
6
7
8
9
public abstract class CPU {
public abstract void showCPU();
}
public abstract class Memory {
public abstract void showMemory();
}
public abstract class HD {
public abstract void showHD();
}

(2)创建产品实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class IntelCPU extends CPU {
@Override
public void showCPU() {
System.out.println("Intet CPU");
}
}
public class SamsungMemory extends Memory {
@Override
public void showMemory() {
System.out.println("三星 内存");
}
}
public class WdHD extends HD {
@Override
public void showHD() {
System.out.println("西部数据 硬盘");
}
}

(3)创建抽象工厂类

1
2
3
4
5
public abstract class ComputerFactory {
public abstract CPU createCPU();
public abstract Memory createMemory();
public abstract HD createHD();
}

(4)创建工厂实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class DellComputerFactory extends ComputerFactory {
@Override
public CPU createCPU() {
return new IntelCPU();
}
@Override
public Memory createMemory() {
return new SamsungMemory();
}
@Override
public HD createHD() {
return new WdHD();
}
}

2.2.3 工厂方法模式

工厂方法模式可以看成是抽象工厂模式的一个特例,当抽象工厂中,只有一种产品时,就和工厂方法一样了。

(1)创建抽象产品类

1
2
3
public abstract class Product {
public abstract void show();
}

(2)创建产品实体类

1
2
3
4
5
6
7
8
9
10
11
12
public class ProductA extends Product {
@Override
public void show() {
System.out.println("product A");
}
}
public class ProductB extends Product {
@Override
public void show() {
System.out.println("product B");
}
}

(3)创建抽象工厂类

1
2
3
public abstract class Factory {
public abstract Product create();
}

(4)创建工厂实体类

1
2
3
4
5
6
7
8
9
10
11
12
public class FactoryA extends Factory {
@Override
public Product create() {
return new ProductA();//创建ProductA
}
}
public class FactoryB extends Factory {
@Override
public Product create() {
return new ProductB();//创建ProductB
}
}

2.3 建造者模式

(1)创建产品实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Computer {
private String mCPU;
private String mMemory;
private String mHD;

public void setCPU(String CPU) {
mCPU = CPU;
}
public void setMemory(String memory) {
mMemory = memory;
}
public void setHD(String HD) {
mHD = HD;
}
}

(2)创建建造者抽象类

1
2
3
4
5
6
public abstract class Builder {
public abstract void buildCPU(String cpu);//组装CPU
public abstract void buildMemory(String memory);//组装内存
public abstract void buildHD(String hd);//组装硬盘
public abstract Computer create();//返回组装好的电脑
}

(3)创建建造者实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ConcreteBuilder extends Builder {
//创建产品实例
private Computer mComputer = new Computer();

@Override
public void buildCPU(String cpu) {//组装CPU
mComputer.setCPU(cpu);
}
@Override
public void buildMemory(String memory) {//组装内存
mComputer.setMemory(memory);
}
@Override
public void buildHD(String hd) {//组装硬盘
mComputer.setHD(hd);
}
@Override
public Computer create() {//返回组装好的电脑
return mComputer;
}
}

(4)创建指挥者实体类,用于控制建造者进行建造任务

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Director {
private Builder mBuild = null;

public Director(Builder build) {
this.mBuild = build;
}
//指挥装机人员组装电脑
public void Construct(String cpu, String memory, String hd) {
mBuild.buildCPU(cpu);
mBuild.buildMemory(memory);
mBuild.buildHD(hd);
}
}

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 中介者模式

当程序存在大量的类时,多个对象之间存在着依赖的关系,呈现出网状结构,那么程序的可读性和可维护性就变差了,并且修改一个类需要牵涉到其他类,不符合开闭原则。

当多个类之间有复杂交互时,通过创建一个中介者类,用于处理其他类之间的交互问题,提高耦合但也提高了代码逻辑清晰度和可读性,在类和类交互时,也不需要针对不同的类定制专用的接口,只需要通过中介者提供的公用接口调用即可。