设计模式:
描述-对代码设计的经验总结,可以重用的代码结构,具有明确的适用场景及适用特点。Java 通用的设计模式有 23 种,按照行为逻辑通常被分为三类:
- 创建型模式(对象实例化):单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式;
- 结构性模式():适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式、代理模式;
- 行为型模式():访问者模式、模板模式、策略模式、状态模式、观察者模式、备忘录模式、中介者模式、迭代器模式、解释器模式、命令模式、责任链模式;
如下对一些常用的设计模式举例:
单例模式
- 描述
单进程中只有一个实例 - 通用写法
public class Object {
private volatile static Object instance;
private Object() {}
/**
* 懒汉式:适用于单线程场景
*/
public static Object getInstanceA() {
if (instance == null) {
instance = new Object();
}
return instance;
}
/**
* 懒汉式:双层检查,线程安全,适用于多线程场景
*/
public static Object getInstanceB() {
if (instance == null) {
synchronized (Object.class) {
if (instance == null) {
instance = new Object();
}
}
}
return instance;
}
/**
*静态内部类方式:线程安全,代码更简洁
*/
public static Object getInstanceC() {
return InnerHolder.objectInstance;
}
private static class InnerHolder {
private static final Object objectInstance = new Object();
}
}
- 使用场景
单例模式主要适用于单应用需要全局实例的场景 - 系统中常用使用场景
系统中使用单例模式的场景也很多,入AMS中通过单例模式获取Watchdog的实例获取watchdog相关信息
Android_T/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
AMS运行在system server中,system server进程启动后ASM也只有一个实例,代码逻辑中也用到很多单例模式构建的实例,记录状态。
工厂方法模式
- 描述
定义一个创建实例的接口,子类通过逻辑判断决定使用哪个实例。 -
通用写法
public abstract class Test {
public abstract void testFactory();
}
public class Func1 extends Test {
@Override
public void testFactory() {
/*
* function 1 test
* */
}
}
public class Func2 extends Test {
@Override
public void testFactory() {
/*
* function 2 test
* */
}
}
public abstract class TestFactory {
public abstract Test test(String s);
public TestFactory getFactory() {
return new TestFactoryImpl();
}
}
public class TestFactoryImpl extends TestFactory {
public Test test(String s) {
if (s != null) {
return new Func1();
} else {
return new Func2();
}
}
}
- 使用场景
工厂方法主要适用于方法有不同的实现,例如View的绘制需要填充不同的布局,Button和ImageView填充的布局和资源都有差异,他们可以通过实现不同的inflate方法填充不同的布局来实现不同的UI配置,总结一下就是工厂方法可以有多个实例继承实现,具体使用哪个实例的工厂方法由工厂类按规则决定具体使用哪个实例。 - 系统使用场景
通常使用的是静态工厂方法,如java中Integer.valueOf()方法。
抽象工厂模式
- 描述
简单来说就是工厂是抽象的,产品也是抽象的,例如一个家具工厂可以生成凳子,桌椅,目前有两个品牌都加工凳子和桌椅,品牌A对凳子桌椅做了圆弧设计加了海绵垫,品牌B对凳子桌椅直角设计加装了玻璃,其中家具工厂即为抽象工厂,品牌A和B为抽象工厂的具体实现,凳子桌椅是要买的产品,品牌A和B对产品做了更精细化的设计。 - 通用写法
public abstract class AbstractFactory {
public abstract ProductA createProductA();
public static AbstractFactory getFactory(String s) {
if (s != null) {
return new FactoryA();
} else {
return new FactoryB();
}
}
}
public abstract class ProductA {
public abstract void productAppple();
}
public class FactoryA extends AbstractFactory{
@Override
public ProductA createProductA() {
return new AA();
}
}
public class AA extends ProductA {
@Override
public void productAppple() {
}
}
public class FactoryB extends AbstractFactory{
@Override
public ProductA createProductA() {
return new BA();
}
}
public class BA extends ProductA {
@Override
public void productAppple() {
}
}
系统中使用抽象工厂典型的一个例子就是Settings中的FeatureFactory,oem厂商可通过FeatureFactory自定义设置项相关UI。
Android_T/packages/apps/Settings/src/com/android/settings/overlay/FeatureFactory.java
建造者模式
- 描述
一个复杂对象需要多个环节进行构造,可以使用建造者模式将构建过程拆解,最终拼装成最终的对象。 -
通用写法
建造者模式进行对象创建大多采用链式逻辑,典型的一个写法是StringBuilder。public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
public StringBuilder() {
super(16);
}
public StringBuilder(int capacity) {
super(capacity);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
调用方使用方法
StringBuilder builder = new StringBuilder()
.append("1")
.append("2")
.append("3");
适配器模式
- 描述
适配器模式简称Adapter,主要用于解决接口不兼容问题。 - 通用写法
public interface A {
void setItemA();
}
public interface B {
void setItemB();
}
public class Adapter implements B {
private A a;
public Adapter(A a1) {
a = a1;
}
@Override
public void setItemB() {
a.setItemA();
}
}
- 系统使用场景
系统中使用适配器模式最常用的写法是ListView
桥接模式
- 描述
将整个对象抽象成一些列独立模块的组合,这些独立模块可以独立演进,设计思路类似于建造者模式。 -
通用写法
public interface Function {
void product();
}
public class AProduce implements Function {
@Override
public void product() {
}
}
public class BProduce implements Function {
@Override
public void product() {
}
}
public class FuctionObj {
private Function function;
public FuctionObj(Function fun) {
function = fun;
}
public void product() {
function.product();
}
}
调用方法
public void product() {
FuctionObj objA = new FuctionObj(new AProduce());
FuctionObj objB = new FuctionObj(new BProduce());
objA.product();
objB.product();
}
- 系统使用场景
系统中使用桥接模式比较常见的的例子就是ViewGroup
组合模式
- 描述
一种结构性的设计模式,也就是将一个对象拆解为整体和部分的模式,如XML解析,整个xml以树形结构存在,存在一系列的子节点和叶子节点,类似与算法中递归的逻辑。 -
通用写法
public class Node {
private Node child;
private String key;
private String value;
public void setChild(Node c) {
child = c;
}
}
public void processNods() {
Node parent = new Node();
Node child = new Node();
parent.setChild(child);
}
- 系统中使用场景
组合模式最常用的使用场景,可以看xml解析过程
装饰模式
- 描述
装饰模式主要描述的将对象和处理对象行为拆分的一种结构性设计模式。 - 通用写法
public interface Obj {
void set(String s);
String get();
}
public class ObjImpl implements Obj {
@Override
public void set(String s) {
}
@Override
public String get() {
return null;
}
}
public abstract class Decorator {
protected Obj warpper;
public abstract void setObj();
public abstract String getObj();
}
public class ProductADecerator extends Decorator {
@Override
public void setObj() {
warpper.set("1");
}
@Override
public String getObj() {
return warpper.get();
}
}
- 系统中的使用场景
装饰模式比较常用的使用场景是Java中的InputStream
外观模式
- 描述
为复杂的对象关系,提供简单的接口调用。外观模式与建造者模式设计思路类似,建造者模式基于对象而言,把一个复杂对象的生成,拆成一个个简单的步骤,这个步骤就只为生成这个对象服务。外观模式基于业务而言,例如我要办理房产证,要先跟银行打交道,再跟房管局打交道,银行和房管局的职能不同,办理房产证业务只是他们职能的一部分。 - 通用写法
public class DepartmentA {
public void processA1(){}
public void processA2(){}
}
public class DepartmentB {
public void processB1(){}
public void processB2(){}
}
public class Business {
public void handleBusiness() {
DepartmentA a = new DepartmentA();
DepartmentB b = new DepartmentB();
a.processA1();
b.processB2();
}
}
public void clientRequest() {
Business business = new Business();
business.handleBusiness();
}
- 系统中的使用场景
系统中外观模式的使用很多,具体可以看看AMS startActivity的流程设计。
享元模式
- 描述
一个是对象实例化之后如果不可变,就会把该对象缓存起来。客户端每次请求该对象是直接从缓存中取出传递给客户端。相比于单例模式,它的差异在于应用进程中是可以有多个实例的。 - 通用写法
public class SharedObj {
public String key;
public String value;
}
public static class SharObjProduct {
public static Map<String, SharedObj> sharedMap;
public static SharedObj getSharedObj(String key) {
if (sharedMap.containsKey(key)) {
return sharedMap.get(key);
}
return null;
}
}
public SharedObj getSharedObj(String s) {
return SharObjProduct.getSharedObj(s);
}
- 系统中的使用场景
系统中常见的场景就是线程池的设计。
代理模式
- 描述
代理模式也是一个结构型的设计模式,即访问一个类A,需要另外一个类B才能访问。系统中常用的Manager-service模式就是典型的代理模式的体现,代理还有远程代理,智能引用等常用的代理方式。 - 通用写法
public class RealObj {
public void process(String s) {}
}
public class ProxyObj {
public void process(String s) {
if (s.equals("1111")) {
RealObj obj = new RealObj();
obj.process(s);
}
}
}
- 系统中的使用场景
系统中比较典型的适用代理模式的场景是系统Service的Manager-service模式。
访问者模式
- 描述
访问者模式是一种行为设计模式,其主要的设计思路是在不改变访问对象数据结构的基础上,根据访问者传递的条件进行结果输出,例如,开发者需要访问一组文件,文件检索的过程都是一样的,但是开发者A需要获取到java文件,开发者B需要获取到的groovy文件。 - 通用写法
public abstract class AbstractVisitor {
public abstract void processA(String s);
public abstract void processB(String s);
}
public class FunctionVisitor extends AbstractVisitor{
@Override
public void processA(String s) {
}
@Override
public void processB(String s) {
}
}
public class Element {
Map<String, String> elementMap;
public void process(String s, FunctionVisitor visitor) {
if (elementMap.containsKey(s)){
visitor.processA(elementMap.get(s));
} else {
visitor.processB(elementMap.get(s));
}
}
}
- 系统中的使用场景
访问者模式一般适用于对象的数据结构和请求数据的行为分开的场景。比较常见的适用场景:检索的适用场景,如在淘宝中搜索“电动车”,它会在他的产品数据库中根据访问者输入的请求类型展示相关的产品。
模板模式
- 描述
模板模式也是一种行为类的设计模式,模板模式理解起来很简单,就是公共的事情父类做,私有的事情子类做。例如,学校安排了手工课,做了一个飞机,飞机的架子是父亲搭的,但是飞机上涂什么颜色,画什么画,小朋友就可以自由发挥了。 - 通用写法
public abstract class ParentObj {
public void process() {
step1();
step2();
step3();
}
private void step1() {}
private void step2() {}
protected abstract void step3();
}
public class ChildObj extends ParentObj {
@Override
protected void step3() {
}
}
public void processObj() {
ChildObj obj = new ChildObj();
obj.process();
}
- 系统中的使用场景
java和我们日常的代码设计中有很多类似使用场景,如java中AbstractList的设计,还有TextView和Button也是一样的设计方式。
策略模式
- 描述
策略模式是一种行为型的设计模式,主要描述的封装一组算法,根据客户端请求的策略来选择使用哪种算法完成客户端的请求,策略模式与访问者模式比较相似只是针对的对象不同,策略模式针对的算法,访问者模式针对的是对象的数据结构。 - 通用写法
public int requestStrategy(int i, int j, String strategy) {
if (strategy.equals("+")) {
return new StrategyAddition().process(i, j);
} else if (strategy.equals("-")) {
return new StrategySubtraction().process(i, j);
}
return i;
}
public class StrategyAddition {
public int process(int i, int j) {
return i+j;
}
}
public class StrategySubtraction {
public int process(int i, int j) {
return i-j;
}
}
- 系统中的使用场景
关于策略模式的使用场景也比较常见,比较典型的一个例子就是地图路径查找,例如输入的是骑行模式,推荐的就行骑行的路线,输入的驾车模式,推荐的就是驾车的路线。
观察者模式
- 描述
观察者模式也可以说成订阅模式,即某一个任务执行发生变化时,它要把他的状态同步给所有订阅该任务状态的订阅者,订阅者根据传递回来的状态做逻辑处理。例如银行打算明年调高存款利息,它会发布一个公告告诉所有的储户,储户收到了这个公告后就把更多的钱存在银行。 - 通用写法
public static class ObserverObj {
List<Listener> listeners;
public interface Listener{
void process();
}
public void addListener(Listener listener) {
listeners.add(listener);
}
public void process() {
for (Listener lis: listeners) {
lis.process();
}
}
}
- 系统中使用场景
观察者模式在系统中使用场景有很多,例如,Android中应用监听自身生命周期变化的场景。
迭代器模式
- 描述
迭代器模式也是一种行为型的设计模式,它的设计初衷是在不暴露一个集合的组织结构的情况能够遍历完集合中所有的元素,例如,学校要收集全校学生的信息,学校把收集信息的任务下发到各个班级,各个班级收集完信息后把信息反馈给学校。 - 通用写法
List<String> list = ...
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
String s = it.next();
}
- 系统中使用场景
系统中使用迭代器模式最常用的场景,就是Map,List中的Iterator<T>
责任链模式
- 描述
责任链模式也是一种行为型的设计模式,它的设计初衷是将任务分发给各个处理者去处理,只要有一个处理者能处理就结束处理过程。例如,家里的小朋友要零花钱,先找爸爸要,爸爸没给,再找妈妈要,妈妈也没给,又找奶奶要,奶奶给了,他就可以去买东西吃了。 - 通用写法
public class Process{
public boolean process1(String s) {
return false;
}
public boolean process2(String s) {
return false;
}
public boolean process3(String s) {
return true;
}
}
public void process123(String s) {
Process pro = new Process();
if (pro.process1(s)) {
return;
} else if(pro.process2(s)) {
return;
} else {
pro.process2(s);
}
}
- 系统中使用场景
系统中比较典型的使用场景就是input事件处理,input事件首先先给Activity处理,如果Activity不处理,再给PhoneWindow处理,如果PhoneWindow处理了,input事件处理就结束了。
总结
目前这23种都有相应的适用场景,在做方案选择是可以通过具体的业务诉求做整合,如下通过表格对各业务场景的适用场景做个简单的总结,期望对大家有一定的帮助。
- 单例模式-适用于单应用需要全局实例的场景。
- 工厂方法模式-适用于对象一对多的场景,具体用哪个实例,由客户端请求决定。
- 抽象工厂模式-适用于对象多对多的场景,具体用哪个实例,由客户端请求的对象工厂决定。
- 建造者模式-适用于对复杂对象就结构性拆分场景,例如Url的拼接等。
- 原型模式-适用于需要生成一个与现有对象 一模一样的对象的一种模式,例如通过入参的方式传递过来的引用,我们要把这个引用固化到逻辑中就需要原型模式。
- 适配器模式-适用于 不兼容的两个对象可以一起合作的场景,例如ListView中数据和View的同步。
- 桥接模式-适用于将复杂对象拆分中一个个可以独立集成的小类,这些小类可以独立演进 例如ViewGroup的结构。
- 组合模式-适用于将一个对象拆解为整体和部分的模式,例如XML解析,整个xml以树形结构存在。
- 装饰模式-适用于将一个对象封装成另外一个对象的成员变量中,通过另外一个对象控制实际对象的输出。
- 外观模式-适用于为一个复杂的逻辑添加一个入口,通过该入口对复杂的调用逻辑做功能拆分,例如startActivity的流程。
- 享元模式-适用于对象实例化之后如果不可变,就会把该对象缓存起来。客户端每次请求该对象是直接从缓存中取出传递给客户端。
- 代理模式-适用于未原对象提供一个替代品做逻辑管控的场景,用于限制对原对象的访问,例如系统的Manager-service模式。
- 访问者模式-适用于在不改变访问对象数据结构的基础上,根据访问者传递的条件进行结果输出。
- 模板模式-适用于不改变父类控制流程的基础上,通过自雷做差异化逻辑的场景。
- 策略模式-适用于封装一组算法,根据客户端请求的策略来选择使用哪种算法完成客户端的请求。
- 状态模式-适用于根据客户端不同的请求返回不同结果的场景。
- 观察者模式-也可以说成订阅模式,适用于客户端服务端的场景,服务端状态发生变化时将变化结果传递给客户端的场景。
- 备忘录模式-适用于需要记录对象状态的场景,例如启动一个应用发生异常时,恢复到异常发生前的场景。
- 中介者模式-适用于创建一个中介对象来封装一些列的交互。
- 迭代器模式-适用于提供一种方法顺序访问一个聚合对象中的各个元素。
- 解释器模式-适用于数据解析的场景,如正则表达式的解析。
- 命令模式-适用于把请求封装成一个命令,然后执行该命令。
- 责任链模式-适用于将任务分发给各个处理者去处理,只要有一个处理者能处理就结束处理过程。