本文用于记录本人阅读完《HeadFirst设计模式》一书后对此书的总结,总结系个人理解并简化提炼,方便使用设计模式时速查,如有错漏,请积极指出,本人将虚心接受并及时改正。

1. 策略模式

1.1 使用前提

多个同类型的不同对象,具有不同表现的同类行为。

1.2 使用方法

  1. 建立父类,将对象中相同的方法整合到父类实现。
  2. 不同的同类型行为建立对应的接口。
  3. 为不同行为实现相应类型的行为接口。
  4. 父类持有行为接口对象,子类初始化具体的行为对象。

1.3 解决的问题

具有相同属性,但行为(功能)不同的同类型事物。

1.4 案例类图

策略模式类图
策略模式类图

2. 观察者模式

2.1 使用前提

某个对象的属性会对其他对象产生影响,且该属性会产生变化。

2.2 使用方法

  1. 建立被观察者接口(注册与移除观察者,通知观察者变化)与观察者接口(观察到变化时触发行为)。
  2. 影响其他对象的对象实现被观察者接口,属性变化时通知观察者。
  3. 被影响的对象实现观察者接口,实现观察到变化时触发的行为。

2.3 解决的问题

当一个对象属性状态改变时,所有依赖他的对象都会收到通知并触发行为。

2.4 案例类图

观察者模式类图
观察者模式类图

3. 装饰者模式

3.1 使用前提

已有类具备基本的属性及功能,但新需求需要在原有类的基础上增加属性及功能,新需求不想影响原有类。

3.2 使用方式

  1. 为原有类A提取父类B,提取出关键方法;
  2. 新建类C继承父类B,实现提取出的关键方法,增加新属性及功能完成新需求;
  3. 新建类D继承父类C,持有一个父类B对象,构造方法需要父类B对象作为参数;
  4. 创建类A的实例并用于创建类D的实例,完成新需求,类D是类A的装饰者。

3.3 解决的问题

在不修改原有类的代码的情况下,为原有类赋予新的属性及功能,达到不影响原有系统的情况下完成新的需求。

3.4 案例类图

装饰者模式类图
装饰者模式类图

4. 工厂模式

4.1 使用前提

有多个具有不同属性或构造方法但有相似功能的同类产物,需根据条件创建不同的对象。

4.2 使用方式

  1. 为所有不同的产物提取父类;
  2. 建立工厂父类,统一工厂的创建目标产物对象的方法;
  3. 为各个产物建立工厂类,工厂实现创建目标产物对象的方法,完成目标产物对象的构造;
  4. 根据条件使用相应的工厂构造出产物。

4.3 解决的问题

需要频繁根据条件创建同类别的不同类的对象时,容易产生大量的重复代码,工厂模式可以将对象的创建过程集中在工厂中,上层只需要使用工厂即可。

4.4 案例类图

工厂模式类图
工厂模式类图

5. 单例模式

5.1 使用前提

一个类只能有一个实例,且这个实例是全局的(全世界独一无二)。

5.2 使用方式

  1. 经典实现:构造方法私有化,静态变量保存单例,提供获取单例的方法,方法中根据单例变量是否为空决定是否调用构造方法;
  2. 改善多线程:在经典实现的基础上对单例变量及构造方法进行双重加锁;
  3. 最佳实现:在经典实现的基础上改造,单例变量由一个静态内部类持有并构造,根据java的类加载机制,第一次获取单例时将触发静态内部类调用单例的构造方法。(延迟加载,线程安全,)

5.3 解决的问题

全局只存在一个该类的实例,保证数据或处理过程的唯一性,并且可以全局使用该实例而无需另外创建实例。

5.4 最佳实现简单例子

1
2
3
4
5
6
7
8
9
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}

6. 命令模式

6.1 使用前提

事件的处理过程需要隐藏,仅暴露事件的整体调用,类似黑盒。

6.2 使用方式

  1. 为事件整体建立控制器类,将各个部分整合出执行命令的方法;
  2. 将事件的各个过程建立相应的命令类,并将它们的实例传递入控制器的执行方法中;
  3. 控制器的执行方法中遍历所有的命令并调用它们的执行方法。

6.3 解决的问题

将各个过程封装避免暴露而产生其他问题,让事件的进行顺利无误,但缺乏灵活与可扩展性。

6.4 案例类图

命令模式类图
命令模式类图

7. 适配器模式

7.1 使用前提

能够直接得到的对象不是所需或所能够处理的对象,需要将该对象包装后再应用。

7.2 使用方式

  1. 为得到的对象A建立一个适配器类B,类B拥有满足所需的属性和方法;
  2. 类B的构造方法中接受一个对象A,并将对象A的属性与方法取出,完成所需的属性赋值与方法处理;
  3. 使用时,用得到的对象A来构建一个适配器B,并用适配器B来满足所需。

7.3 解决的问题

让本不能满足需求或不能被处理的对象变得满足需求或可以被处理。

7.4 案例类图

适配器模式类图
适配器模式类图

8 外观模式

8.1 使用前提

一个系统可完成多个功能,每个功能由多个子系统配合完成,将每个功能单独封装可以让系统更便于使用。

8.2 使用方式

  1. 为系统建立外观类,为系统的各个功能构建方法;
  2. 外观类的功能方法中整合子系统完成系统的该功能;
  3. 使用时仅暴露外观类,子系统隐藏,方便用户直接使用系统功能。

8.3 解决的问题

为系统提供一个上层接口,方便用户调用,让系统底层子接口易于使用。

8.4 案例类图

外观模式类图
外观模式类图

9 模板方法模式

9.1 使用前提

多个事件具有多个相似的过程,并且这些事件发生的场景类似。

9.2 使用方式

  1. 为这些事件提取父类,这些事件相同的过程由父类统一实现;
  2. 事件的过程相似但区别细微,这些过程可由父类构建抽象方法,由子类自行实现;
  3. 事件有需要根据条件执行或执行某方法后需要执行额外方法时,可用Hook实现。

9.3 解决的问题

让相似的事件抽离成算法框架,具体子步骤可由子类实现不同的具体行为。

9.4 案例类图

模板方法模式类图
模板方法模式类图

10 迭代器模式

10.1 使用前提

需要遍历集合中的对象,但不想暴露对象的存储方式。

10.2 使用方式

  1. 建立迭代器类,持有目标对象的集合(列表/图等等);
  2. 迭代器类实现安卓系统提供的Iterator接口,并实现相应方法。

此模式有系统接口帮助使用,方便快捷。

10.3 解决的问题

提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

10.4 案例类图

迭代器模式类图
迭代器模式类图

11 组合模式

11.1 使用前提

集合的元素也可能是一个集合,需要对集合的各个元素进行处理。

11.2 使用方式

  1. 为集合类与元素类提取组件接口,包含集合类和元素类共同的性质与功能;
  2. 让集合类与元素类均实现组件接口,集合类将属于元素类的性质与功能委托给自己的元素去完成,元素类处理集合类的性质与功能时将自身当成大小为1的集合。

11.3 解决的问题

让集合与元素可以用同样的方式被使用到业务中去。

组合模式与迭代器模式共同使用可以达到1+1>2的效果

11.4 案例类图

组合模式类图
组合模式类图

12 状态模式

12.1 使用前提

一个系统的行为由多个不同但相互联系并能在一定情况下转变的状态所控制。

12.2 使用方式

  1. 将系统中会受到影响的行为方法提取到一个状态接口中;
  2. 根据系统状态的不同建立不同的状态类,状态类实现状态接口,并根据需要实现相应的行为方法;
  3. 当系统状态变化时,将委托对应的状态类完成相应的行为。

12.3 解决的问题

让对象在内部状态改变时,轻易的改变自己的行为。

12.4 案例类图

状态模式类图
状态模式类图

13 代理模式

13.1 使用前提

目标对象不可以直接访问,但需要使用该对象的信息或功能。

13.2 使用方式

  1. 在目标对象的有效区域内,建立目标对象的代理类,代理类持有目标对象或拥有访问目标对象的能力,并将目标对象的属性及功能包装后暴露出去;
  2. 在使用方也可建立使用代理类,用于对接目标代理类,也可直接访问目标代理类,最终完成对目标对象的间接访问。

13.3 解决的问题

让代理访问目标对象,可保证访问的成功与安全,用于需要远程访问/直接访问开销巨大/需要安全保障的对象。

13.4 案例类图

代理模式类图
代理模式类图

14 设计模式总结

14.1 复合模式

模式与模式可以携手合作,多个模式的复合模式就成了架构,让合适的模式出现在合适的位置就是优秀的架构。

书中提及了MVC,将设计模式称为MVC的钥匙,解读了MVC中对于设计模式的复合使用。在这字里行间,MVP和MVVM都可以拆解出一个个的设计模式,设计模式就是框架的基础,框架就是模式与模式的复合。

14.2 与设计模式相处

  1. 用模式思考;
  2. 保持简单;
  3. 模式不是万能的;
  4. 明确何时该使用模式;
  5. 利用模式进行重构;
  6. 删除不需要的;
  7. 现在不需要就别用。

总结

  1. 知道能不能用;
  2. 知道该不该用;
  3. 把握用不用的度。