按照模式的应用目标分类,设计模式可以分为创建型模式、结构型模式和行为型模式:

  • 创建型模式,是对对象创建过程的各种问题和解决方案的总结,包括各种工厂模式(Factory、Abstract Factory)、单例模式(Singleton)、构建器模式(Builder)、原型模式(ProtoType)
  • 结构型模式,是针对软件设计结构的总结,关注于类、对象继承、组合方式的实践经验,常见的结构型模式,包括桥接模式(Bridge)、适配器模式(Adapter)、装饰者模式(Decorator)、代理模式(Proxy)、组合模式(Composite)、外观模式(Facade)、享元模式(Flyweight)等
  • 行为型模式,是从类或对象之间交互、职责划分等角度总结的模式,比较常见的行为型模式有策略模式(Strategy)、解释器模式(Interpreter)、命令模式(Command)、观察者模式(Observer)、迭代器模式(Iterator)、模板方法模式(Template Method)、访问者模式(Visitor)

单例模式(Singleton)

目的:保证在整个应用中某一个类有且只有一个实例,而且自行实例化并向整个系统提供这个实例

工具类的设计

工具类在开发中其实只需要存在一个对象即可

  • 如果工具方法没有使用 static 修饰,说明工具方法得使用工具类的对象来调用,此时应把工具类设计为单例
  • 如果工具方法全部使用 static 修饰,说明工具方法只需要使用工具类名调用即可,此时必须把工具类的构造器私有化

饿汉式(Eager Singleton)

  • 在类装载的时候就创建对象实例
  • 使用场景:java.lang.Runtime
  1. public class Singleton {
  2. // 本类中创建 private static final 修饰的本类对象实例
  3. private static final Singleton instance = new Singleton();
  4. // 私有化构造器
  5. private Singleton() {}
  6. // 提供一个 public static 修饰的方法返回此对象实例
  7. public static Singleton getInstance() {
  8. return instance;
  9. }
  10. }
  11. public class Singleton {
  12. // 私有化构造器
  13. private Singleton() {}
  14. // 静态内部类不会在单例类加载时就加载,而是在调用 getInstance() 方法时才进行加载
  15. private static class SingletonHolder {
  16. private static Singleton instance = new Singleton();
  17. }
  18. public static Singleton getInstance() {
  19. return SingletonHolder.instance;
  20. }
  21. }

懒汉式 / 懒加载(Lazy Singleton)

  • 每次获取实例都会进行判断,看是否需要创建实例
  • “双重检查加锁”机制:不是每次进入 getInstance() 方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在才进行下面的同步块,这是第一重检查,进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。
  1. public class Singleton {
  2. // 本类中定义 private static volatile 修饰的、引用为空的类变量
  3. private static volatile Singleton instance = null;
  4. // 私有化构造器
  5. private Singleton() {}
  6. // 提供一个 public static 修饰的方法返回对象实例
  7. public static Singleton getInstance() {
  8. // 先检查实例是否存在,如果不存在才进入下面的同步块
  9. if (instance == null) {
  10. synchronized (Singleton.class) {
  11. // 双重检测锁:再次检查实例是否存在,如果不存在才真正的创建实例
  12. if (instance == null) {
  13. instance = new Singleton();
  14. }
  15. }
  16. }
  17. return instance;
  18. }
  19. }

使用枚举类做单例模式

  • 定义一个包含单个元素的枚举类型
  1. public enum Singleton {
  2. INSTANCE;
  3. }
  4. // 调用
  5. Singleton.INSTANCE.sort(null);

模板方法模式(Template Method)

  • 在采用某个算法的框架,需要对它的某些部分进行改进
  • 抽象父类的一个方法中定义该方法的总体算法的骨架(模板方法),而把其中某些具体的步骤(不能实现的部分)抽象成抽象方法,延迟到子类中去实现

  • 抽象父类至少提供的方法:

    • 模板方法:一种通用的处理方式,即模板(总体算法的骨架)
    • 抽象方法:一种具体的业务功能实现,由子类完成

使用场景:JDBCTemplate、JUC中的 AQS

  1. public abstract class OperateTimeTemplate{
  2. // 模板方法:总体算法的骨架,子类不能修改
  3. public final long getTotalTime() {
  4. long begin = System.currentTimeMillis();
  5. this.doWork(); // 具体的步骤(延迟到子类中去实现)
  6. long end = System.currentTimeMillis();
  7. return end - begin;
  8. }
  9. // 抽象方法
  10. protected abstract void doWork();
  11. }
  12. public class StringOperate extends OperateTimeTemplate {
  13. public void doWork() {
  14. String str = "";
  15. for (int i = 0; i < 10000; i++) {
  16. str += i;
  17. }
  18. }
  19. }
  20. // 调用
  21. new StringOperate().getTotalTime()

装饰器模式(Decorator Pattern)

  • 在不必改变源代码基础上,动态地扩展一个对象的功能
  • 通过创建一个包装对象,包裹真实的对象
  • 使用场景:IO 流中的包装流、Servlet 中的敏感字过滤
  • 特点:
    • 装饰对象和真实对象有相同的接口
    • 装饰对象包含一个真实对象的引用(多用组合,少用继承)
    • 装饰对象接受所有来自客户端的请求,并把这些请求转发给真实的对象
    • 装饰对象可以在转发这些请求以前或以后增加一些附加功能

适配器模式(Adapter Pattern)

  • 将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作

代理模式(Proxy Pattern)

  • 客户端不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象

策略模式(Strategy Pattern)

  • 策略模式代表了解决一类算法的通用解决方案,需要在运行时选择使用哪种方案
  • 定义一系列的算法,并将每一个算法封装起来,而且使它们可以相互替换,让算法独立于使用它的客户而独立变化
  • 策略模式包含三部分内容
    • 一个代表某个算法的接口(它是策略模式的接口)
    • 一个或多个该接口的具体实现,它们代表了算法的多种实现
    • 一个或多个使用策略对象的客户

观察者模式

  • 某些事件发生时(比如状态转变),一个对象(主题)需要自动地通知其他多个对象(观察者)

责任链模式

  • 一种创建处理对象序列(比如操作序列)的通用方案:一个处理对象可能需要在完成一些工作之后,将结果传递给另一个对象,这个对象接着做一些工作,再转交给下一个处理对象,以此类推

工厂模式

  • 无需向客户暴露实例化的逻辑就能完成对象的创建
  • Spring 中:BeanFactory 和 ApplicationContext

迭代器模式

  • 提供一个一致的方法来顺序访问集合中的对象,这个方法与底层的集合的具体实现无关
  • JDK 中:java.util.Iterator、java.util.Enumeration

享元模式

  • 使用缓存来加速大量小对象的访问时间
  • JDK 中:java.lang.Integer#valueOf(int)、java.lang.Boolean#valueOf(boolean)、java.lang.Byte#valueOf(byte)、java.lang.Character#valueOf(char)