设计模式学习笔记
Jin Hu

设计模式是对软件设计问题常见问题的通用解决方案,使用设计模式可以提高代码的可读性、可维护性和复用性。此外,设计模式还为设计决策提供了共同的语言和框架。

一般来说,设计模式可以分为三类:创建型模式、结构型模式、行为模式。

  • 创建型模式提供了对象创建和使用分离的机制。
  • 结构型模式关注对象和类如何组装成更大结构的方式。
  • 行为模式负责对象之间的沟通协作和职责委派。

学习资料:设计模式目录:22种设计模式图说设计模式 — Graphic Design Patterns

一、创建型(5)

创建型模式提供了对象创建和使用分离的机制。

包括单例模式、建造者模式、工厂方法模式、抽象工厂模式、原型模式。

单例模式

设计模式 - Java中单例模式的6种写法及优缺点对比 - 瘦风 - 博客园

单例模式保证一个类只有一个实例,并提供访问这个实例的全局节点,比如Java中的Runtime、DriverManager等,Spring中的bean默认也都是单例的。

饿汉式

  • 优点:线程安全;
  • 缺点:类初始化时就实例化,但也许不会被使用,浪费内存(一般单例类用于全局资源管理,涉及较多资源,因此使用时再实例化更好)
1
2
3
4
5
6
7
8
9
10
class SingletonHungry {
private static SingletonHungry instance = new SingletonHungry();

private SingletonHungry() {
}

public static SingletonHungry getInstance() {
return instance;
}
}

懒汉式

  • 优点:延迟加载,节省内存;
  • 缺点:线程不安全,多线程环境下可能会创建多个实例;
  • 缺点(加锁):线程安全,但效率低,只允许一个线程访问;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class SingletonLazy {
private static SingletonLazy instance;

private SingletonLazy() {
}

/** 需要保证线程安全可以使用synchronized关键字 */
public synchronized static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
// public static SingletonLazy getInstance() {
// if (instance == null) {
// instance = new SingletonLazy();
// }
// return instance;
// }
}

双重校验锁

  • 优点:延迟加载,节省内存;线程安全;
  • 缺点:需要JDK1.5以上版本支持(volatile关键字在JDK1.5版本后才能保证其可见性);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class SingletonDoubleCheck {
private static volatile SingletonDoubleCheck instance;

private SingletonDoubleCheck() {
}

public static SingletonDoubleCheck getInstance() {
if (instance == null) {
synchronized (SingletonDoubleCheck.class) {
if (instance == null) {
instance = new SingletonDoubleCheck();
}
}
}
return instance;
}
}

为什么需要用volatile?

Java创建对象并不是原子操作,为了避免这个过程中的重排序,出现半个对象问题,使用Volatile禁止重排序,并保证多线程可见性

(比如避免new到一半被其他线程调用。)

静态内部类(推荐)

优点:1)延迟加载,节省内存(在调用getInstance()方法时才会加载SingletonHolder类);2)JVM保证线程安全(类加载是线程安全,且只加载一次)。

1
2
3
4
5
6
7
8
9
10
11
12
class SingletonStaticInner {
private SingletonStaticInner() {
}

private static class SingletonHolder {
private static final SingletonStaticInner INSTANCE = new SingletonStaticInner();
}

public static SingletonStaticInner getInstance() {
return SingletonHolder.INSTANCE;
}
}

枚举

优点:线程安全,防止序列化攻击和反射攻击。

缺点:所有属性必须在创建时指定,不可以延迟加载;占用内存比静态变量高。

1
2
3
4
5
6
7
enum SingletonEnum {
INSTANCE; // 通过SingletonEnum.INSTANCE调用

public void method() {
System.out.println("SingletonEnum method");
}
}

破坏单例模式的方式

  1. 反射:可以在构造函数中判断是否存在实例,存在直接抛出异常
  2. 序列化攻击:通过反序列化破坏单例▶不实现序列化接口,或者反序列化直接返回相关单例对象。
  3. Clone:通过重写clone方法,抛出异常禁止复制(因为clone在Object中,不管是否实现Cloneable接口都可能被破坏)

建造者模式(Builder、生成器模式)

建造器模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

我的理解其实就是抽象出一个复杂对象的构建过程,向外提供一系列方法,提高代码可读性和可维护性。

比如Java中的StringBuilder,lombok的@Builder注解会生成建造者模式相关代码。

这里通常也会和写成流式接口,可以链式调用。

工厂方法模式

工厂模式超详解(代码示例)_工厂模式代码-CSDN博客

简单工厂模式将创建对象的过程交给工厂类负责,需要创建对象时直接找工厂获取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TeaFactory {
public ITea createTea(String type) {
ITea tea = null;
if (type.equals("longjing")) {
tea = new LongjingTea();
} else if (type.equals("biluochun")) {
tea = new BiluochunTea();
}
if (tea != null) {
tea.makeTea();
}
return tea;
}
}

但是如果需要需要新增产品还需要修改原来的工厂类,不符合开闭原则;工厂类还需要负责每个产品的创建过程,不符合单一职责原则。

工厂方法模式将工厂也进行了抽象,提供了工厂接口,每种对象需要实现对相应的工厂类,由具体工厂类去决定实例化的对象。

也就是包括抽象工厂接口、具体工厂类、抽象产品、具体产品类。

1
ITeaFactory factory = new LongjingTeaFactory();

比如Java中的Calendar、Spring的BeanFactory、JDBC的DriverManager都是工厂模式。

抽象工厂模式

抽象工厂模式是在工厂模式基础上,可以创建一系列相关对象。

比如UI组件库(如按钮、文本框等)。

原型模式

原型模式用于通过克隆创建重复对象,省略了复杂对象创建过程,适合需要大量重复对象的场景。

需要实现Cloneable接口,比如Spring中指定bean为prototype模式,就会开启原型模式。

二、结构型(7)

结构型模式关注对象和类如何组装成更大结构的方式

包括适配器模式桥接模式、组合模式、装饰者模式外观模式、享元模式、代理模式

适配器模式

《JAVA与模式》之适配器模式 - java_my_life - 博客园

适配器模式是当接口不兼容时,引入适配器类允许将一个类转换为期望接口,使得原本不能一起工作的类一起工作。将接口之间解耦,扩展功能,增加复用性。

实现适配器模式有类适配器、对象适配器两种方式。

类适配器:将源类的方法转化为目标接口的方法,定义适配器类继承自源类并实现目标接口进行方法重写和转化。

对象适配器:定义适配器类继承/实现目标接口,里面包含一个源类对象,补充源类缺失的目标接口方法。

适用场景:第三方库不兼容,Java中的IO库通过适配器模式对不同的数据源进行适配。

桥接模式

桥接模式是指将抽象和实现分离,使得两者可以独立变化,适用于多个维度变化的场景。直白说就是抽象类里有抽象类对象。优势是解耦,扩展性强。

个人觉得三层架构实现就是桥接模式。

组合模式

组合模式是指将对象组合为属性

装饰器模式

外观模式

享元模式

代理模式

三、行为型(11)

行为模式负责对象之间的沟通协作和职责委派。

包括责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式模板方法模式、访问者模式。

 评论