1.工厂模式:

image-20260313170811459

工厂模式是一类创建型设计模式,目的是把对象的创建过程从使用者代码中分离出来,降低耦合、集中管理创建逻辑、方便扩展与测试;

简单工厂,抽象工厂,工厂方法等;

工厂模式的核心思想是:

1
2
依赖倒置原则(DIP)
高层模块不依赖低层模块,二者都依赖抽象

如果在Service中new 对象 , 那么Service类 就会依赖于这个对象类;
但是如果使用工厂模式,那么Service类和对象类就都依赖于工厂类,符合了依赖倒置原则;

实现了解耦:

在配置环境中配置:

1
logger.type=file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class LoggerFactory {

public static Logger createLogger(){

String type = Config.get("logger.type");

switch(type){
case "file":
return new FileLogger();
case "console":
return new ConsoleLogger();
}

throw new RuntimeException();
}

}

就可以通过修改配置文件来实现不同逻辑,而不用去修改代码

例如简单工厂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Product 接口与实现
public interface Shape {
void draw();
}

public class Circle implements Shape {
public void draw() { System.out.println("draw circle"); }
}
public class Rectangle implements Shape {
public void draw() { System.out.println("draw rectangle"); }
}

// SimpleFactory
public class ShapeFactory {
public static Shape create(String type) {
return switch (type) {
case "circle" -> new Circle();
case "rect" -> new Rectangle();
default -> throw new IllegalArgumentException("unknown type: " + type);
};
}
}

// 使用
public class Main {
public static void main(String[] args) {
Shape s1 = ShapeFactory.create("circle");
s1.draw(); // draw circle
}
}

现代/实用写法:注册式工厂(Java 8+)

如果你不想为每个产品写一堆工厂类,可以用 Map<String, Supplier<T>> 注册工厂函数,便于扩展与配置(更贴近现代代码风格)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.*;
import java.util.function.Supplier;

public class RegistryFactory {
private static final Map<String, Supplier<Shape>> map = new HashMap<>();

static {
map.put("circle", Circle::new); // 通过方法引用注册
map.put("rect", Rectangle::new);
}

public static Shape create(String key) {
Supplier<Shape> s = map.get(key);
if (s == null) throw new IllegalArgumentException("unknown: " + key);
return s.get();
}

// 运行时注册
public static void register(String key, Supplier<Shape> supplier) {
map.put(key, supplier);
}
}

这种方式便于通过配置文件或反射在运行时注册新类型,适合插件式架构。

Java 8 中引入了一组函数式接口,用于支持 Lambda 表达式和函数式编程,其中 Supplier 就是非常重要的一个接口。Supplier 位于 java.util.function 包中,它表示一个数据提供者(生产者),特点是不接收任何参数,但是会返回一个结果。从接口定义可以看出它的设计非常简单,本质上就是一个“提供数据”的函数。源码如下:

1
2
3
4
@FunctionalInterface
public interface Supplier<T> {
T get();
}

这里的泛型 T 表示返回的数据类型,而 get() 方法就是唯一的抽象方法。当调用 get() 时,就会返回一个对象。因此可以理解为:Supplier 的作用就是在需要的时候提供一个对象或数据。由于它只有一个抽象方法,因此它是一个典型的函数式接口,可以直接使用 Lambda 表达式方法引用 来实现。例如:

1
2
3
4
5
6
7
8
9
10
11
12
import java.util.function.Supplier;

public class Test {
public static void main(String[] args) {

Supplier<String> supplier = () -> "Hello World";

String result = supplier.get();

System.out.println(result);
}
}

在这段代码中,Supplier<String> 表示这个 Supplier 会返回一个 String 类型的数据,Lambda 表达式 () -> "Hello World" 实际上就是实现了 get() 方法。当调用 supplier.get() 时,就会返回 "Hello World" 并输出到控制台。这种写法相比传统的匿名内部类更加简洁。例如,如果不用 Lambda 表达式,传统写法如下:

1
2
3
4
5
6
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return "Hello World";
}
};

可以看到,Lambda 表达式极大简化了代码。

2.策略模式:

image-20260313170844304

是一种行为型设计模式,它的核心思想是:定义一系列算法或行为,并将每一种算法封装起来,使它们可以相互替换,从而让算法的变化独立于使用算法的客户端

例如早期使用jdbc时需要用Class.forName(“com.mysql.cj.jdbc.Driver”);来配置mysql;也可以通过修改参数来切换到Oracle等;

如果使用switch语句或者if-else语句,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class PayService {

public void pay(String type, double amount) {

if ("alipay".equals(type)) {
System.out.println("使用支付宝支付:" + amount);
} else if ("wechat".equals(type)) {
System.out.println("使用微信支付:" + amount);
} else if ("bank".equals(type)) {
System.out.println("使用银行卡支付:" + amount);
} else {
throw new RuntimeException("不支持的支付方式");
}
}

}

每增加一种新的支付方式,都需要修改原有代码。如果支付方式越来越多,这个方法会变得非常臃肿,同时违反了设计原则中的开闭原则(对扩展开放:当需求发生变化时,我们可以通过添加新的代码来增强系统的功能 ,对修改关闭:在不修改原有源代码的前提下,实现功能的变更); 策略模式正是为了解决这种问题。

策略模式的基本实现步骤通常包括三个部分。第一部分是定义一个策略接口,这个接口规定所有具体策略必须实现的行为。例如在支付系统中,我们可以定义一个支付策略接口:

1
2
3
interface PayStrategy {
void pay(double amount);
}

这个接口代表“支付策略”,任何具体支付方式都必须实现 pay 方法。接下来我们创建多个具体策略类,每个类实现一种具体的支付方式。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class AliPayStrategy implements PayStrategy {

@Override
public void pay(double amount) {
System.out.println("使用支付宝支付:" + amount);
}
}

class WechatPayStrategy implements PayStrategy {

@Override
public void pay(double amount) {
System.out.println("使用微信支付:" + amount);
}
}

class BankPayStrategy implements PayStrategy {

@Override
public void pay(double amount) {
System.out.println("使用银行卡支付:" + amount);
}
}

这里每一个类都代表一种具体策略(Concrete Strategy)。每个策略类都实现了同一个接口,因此它们之间可以互相替换。接下来需要一个**上下文类(Context)**来使用这些策略。上下文类并不关心具体是哪一种支付方式,它只依赖策略接口:

1
2
3
4
5
6
7
8
9
10
11
12
class PayContext {

private PayStrategy strategy;

public PayContext(PayStrategy strategy) {
this.strategy = strategy;
}

public void executePay(double amount) {
strategy.pay(amount);
}
}

在这个 PayContext 类中,真正执行支付的逻辑是调用 strategy.pay()。由于 strategy 是接口类型,因此可以在运行时传入任何具体实现类。最后在客户端代码中,我们可以根据需要选择不同的策略:

1
2
3
4
5
6
7
8
9
10
11
public class Test {

public static void main(String[] args) {

PayStrategy strategy = new AliPayStrategy();

PayContext context = new PayContext(strategy);

context.executePay(100);
}
}

如果现在需要改为微信支付,只需要更换策略对象即可:

1
2
3
PayStrategy strategy = new WechatPayStrategy();
PayContext context = new PayContext(strategy);
context.executePay(100);

可以看到,客户端代码不需要修改业务逻辑,只是替换策略对象。如果未来新增一种支付方式,例如 ApplePayStrategy,只需要新增一个实现类即可,而不需要修改已有代码,这就实现了“对扩展开放,对修改关闭”

在实际项目中,策略模式通常会和工厂模式结合使用,以避免客户端直接 new 不同的策略类。例如可以通过工厂根据类型返回对应的策略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class PayStrategyFactory {

public static PayStrategy create(String type) {

switch (type) {
case "alipay":
return new AliPayStrategy();
case "wechat":
return new WechatPayStrategy();
case "bank":
return new BankPayStrategy();
default:
throw new RuntimeException("不支持的支付方式");
}
}
}

客户端代码可以写成:

1
2
3
4
5
6
7
8
9
10
11
public class Test {

public static void main(String[] args) {

PayStrategy strategy = PayStrategyFactory.create("alipay");

PayContext context = new PayContext(strategy);

context.executePay(200);
}
}

这样就把策略选择逻辑策略执行逻辑进一步解耦。

3.备忘录模式

image-20260313170902741

**备忘录模式(Memento Pattern)*是一种*行为型设计模式,它的核心思想是:

在不破坏对象封装性的前提下,捕获对象的内部状态,并在需要的时候恢复到之前的状态。

简单理解就是:
给对象做“快照”,需要的时候可以恢复到过去的某个状态。

常见场景:

  • 撤销(Undo)功能:文本编辑器撤销操作
  • 回滚操作:数据库事务回滚
  • 游戏存档:保存和读取游戏进度

一、备忘录模式的角色

备忘录模式通常有 三个角色

角色 作用
Originator(发起人) 需要保存状态的对象
Memento(备忘录) 用来存储对象状态
Caretaker(管理者) 负责保存和恢复备忘录

关系结构:

1
2
3
4
5
Originator  ----创建---->  Memento
↑ |
| |
--------恢复状态-----------
Caretaker

4.代理模式

image-20260313170914310

**代理模式(Proxy Pattern)*是一种*结构型设计模式
它的核心思想是:

为某个对象提供一个代理对象,由代理对象控制对原对象的访问。

简单理解:

1
客户端 -> 代理对象 -> 真实对象

客户端不直接访问真实对象,而是通过代理对象访问。

代理对象可以在调用真实对象方法 前后增加额外功能

Spring Aop底层用的就是动态代理;

代理模式是为了保证原对象的安全,不去暴露太多原对象的信息; 同时代理类内有前置,后置方法,可以在真实对象中添加其他的逻辑;

一、代理模式的结构

代理分为静态代理动态代理

静态代理是由程序写死的,动态代理是运行时动态生成的;

对于静态代理类,对每个类都要写一个代理类,会导致一个代码爆炸的问题;

代理模式一般有三个角色:

角色 作用
Subject(抽象主题) 定义公共接口
RealSubject(真实对象) 真正执行业务逻辑
Proxy(代理对象) 控制对真实对象的访问

结构图:

1
2
3
4
5
6
7
        Subject

----------------
| |
RealSubject Proxy
|
RealSubject

调用流程:

1
2
3
4
5
Client

Proxy

RealSubject

二、静态代理(Static Proxy)

静态代理指的是:

代理类在编译时就已经确定。


示例:用户服务代理

1 定义接口(Subject)

1
2
3
4
5
public interface UserService {

void login();

}

2 实现真实对象(RealSubject)

1
2
3
4
5
6
7
8
public class UserServiceImpl implements UserService {

@Override
public void login() {
System.out.println("用户登录...");
}

}

3 创建代理类(Proxy)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class UserServiceProxy implements UserService {

private UserService userService;

public UserServiceProxy(UserService userService) {
this.userService = userService;
}

@Override
public void login() {

System.out.println("记录日志...");

userService.login();

System.out.println("记录结束...");
}
}

代理类做了什么:

1
2
3
前置增强
调用真实对象
后置增强

4 测试代码

1
2
3
4
5
6
7
8
9
10
11
12
public class Test {

public static void main(String[] args) {

UserService userService = new UserServiceImpl();

UserService proxy = new UserServiceProxy(userService);

proxy.login();
}

}

输出:

1
2
3
记录日志...
用户登录...
记录结束...

四、JDK动态代理

JDK 提供了:

1
java.lang.reflect.Proxy

可以 在运行时动态生成代理类

要求:

1
必须基于接口

示例

1 接口

1
2
3
4
5
public interface UserService {

void login();

}

2 实现类

1
2
3
4
5
6
7
8
public class UserServiceImpl implements UserService {

@Override
public void login() {
System.out.println("用户登录...");
}

}

3 InvocationHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class LogHandler implements InvocationHandler {

private Object target;

public LogHandler(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {

System.out.println("方法执行前记录日志");

Object result = method.invoke(target, args);

System.out.println("方法执行后记录日志");

return result;
}
}

4 创建代理对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.lang.reflect.Proxy;

public class Test {

public static void main(String[] args) {

UserService userService = new UserServiceImpl();

UserService proxy = (UserService) Proxy.newProxyInstance(
userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
new LogHandler(userService)
);

proxy.login();
}

}

输出:

1
2
3
方法执行前记录日志
用户登录...
方法执行后记录日志

5.单例模式:

image-20260313170930016

**单例模式(Singleton Pattern)*是一种*创建型设计模式
它的核心思想是:

保证一个类在整个系统中只有一个实例,并提供一个全局访问点。

也就是说:

1
2
3
4
5
一个类

只能创建一个对象

所有地方都使用这个对象

常见使用场景:

1
2
3
4
5
线程池
数据库连接池
配置管理类
Spring Bean(默认单例)
日志对象

Sping中的Bean默认就是单例的,IOC容器管理它的生命周期,容器关闭,Bean也随之销毁; 对于多例的Bean可以使用@Scope注解来设置; 但是IOC容器只负责创建,不负责完整生命周期管理,需要自己来主动销毁;

实现方式一:饿汉式

特点:类加载时就创建对象

代码示例

1
2
3
4
5
6
7
8
9
10
11
public class Singleton {

private static final Singleton INSTANCE = new Singleton();

private Singleton() {
}

public static Singleton getInstance() {
return INSTANCE;
}
}

实现方法一:懒汉式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton {

private static Singleton instance;

private Singleton() {
}

public static Singleton getInstance() {

if (instance == null) {
instance = new Singleton();
}

return instance;
}

}

实现方式二:同步锁懒汉式

解决线程安全问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Singleton {

private static Singleton instance;

private Singleton() {
}

public static synchronized Singleton getInstance() {

if (instance == null) {
instance = new Singleton();
}

return instance;
}
}

优点:

1
线程安全

缺点:

1
2
性能差
每次都加锁

实现方式三:双重检查锁(DCL)

这是面试最常问的单例写法。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Singleton {

private static volatile Singleton instance;

private Singleton() {
}

public static Singleton getInstance() {

if (instance == null) {

synchronized (Singleton.class) {

if (instance == null) {

instance = new Singleton();

}

}
}

return instance;
}
}

为什么要 volatile

创建对象实际上有三步:

1
2
3
1 分配内存
2 初始化对象
3 指向内存

JVM 可能发生:

1
指令重排序

变成:

1
2
3
1 分配内存
3 指向内存
2 初始化对象

其他线程可能拿到:

1
未初始化对象

volatile 可以:

1
禁止指令重排序

6.迭代器模式

image-20260313170941755

迭代器模式属于行为型设计模式。它的目的是为聚合对象提供一种顺序访问其元素的方法,而无需暴露该对象的内部表示

参与者(通常约定)

  • Iterator(抽象迭代器):定义访问和遍历元素的接口,例如 hasNext(), next()
  • ConcreteIterator(具体迭代器):实现迭代器接口,对聚合进行遍历的具体算法与状态。
  • Aggregate(抽象聚合):定义创建迭代器的接口,例如 iterator()
  • ConcreteAggregate(具体聚合):实现创建相应迭代器的工厂方法并持有元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 抽象迭代器
public interface MyIterator<T> {
boolean hasNext();
T next();
// 可选:void remove();
}

// 抽象聚合
public interface MyAggregate<T> {
MyIterator<T> iterator();
}

// 具体聚合(内部用 ArrayList 存储)
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;

public class ConcreteAggregate<T> implements MyAggregate<T> {
private final List<T> items = new ArrayList<>();

public void add(T item) {
items.add(item);
}

public T get(int index) {
return items.get(index);
}

public int size() {
return items.size();
}

@Override
public MyIterator<T> iterator() {
return new ConcreteIterator();
}

// 内部具体迭代器
private class ConcreteIterator implements MyIterator<T> {
private int cursor = 0; // 当前索引

@Override
public boolean hasNext() {
return cursor < items.size();
}

@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return items.get(cursor++);
}

// 可选实现 remove(),需要注意并发修改和索引调整
}

}

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class IteratorDemo {
public static void main(String[] args) {
ConcreteAggregate<String> menu = new ConcreteAggregate<>();
menu.add("咖啡");
menu.add("奶茶");
menu.add("果汁");

MyIterator<String> it = menu.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}

// 也可以同时创建多个迭代器互不干扰
MyIterator<String> it2 = menu.iterator();
if (it2.hasNext()) {
System.out.println("第一个元素: " + it2.next());
}
}

}

7.访问者模式

image-20260313170956107

是一种行为型设计模式
核心思想是:将“数据结构”和“作用在数据结构上的操作”分离,从而在不修改数据结构类的情况下,新增新的操作

简单理解一句话:

对象结构稳定,但需要在其上执行的操作经常变化 → 使用访问者模式

一、访问者模式解决什么问题

假设有一个系统:

1
2
3
4
公司员工:
- 程序员
- 产品经理
- 设计师

公司需要做不同的统计:

1️⃣ CEO视角

  • 程序员:看代码量
  • 产品经理:看产品数
  • 设计师:看设计稿数

2️⃣ CTO视角

  • 程序员:看技术能力
  • 产品经理:看逻辑能力
  • 设计师:看创意能力

如果不用访问者模式:

1
2
3
4
5
6
7
8
9
class Programmer {
void acceptCEO(){...}
void acceptCTO(){...}
}

class Manager {
void acceptCEO(){...}
void acceptCTO(){...}
}

问题:

  • 类越来越臃肿
  • 新增角色必须修改所有类
  • 违反开闭原则

访问者模式就是为了解决这个问题。


二、访问者模式结构

访问者模式包含 5个角色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
           Visitor(访问者接口)
/ \
CEOVisitor CTOVisitor
|
visit(Programmer)
visit(Manager)

---------------------------------

Element(元素接口)
|
Employee
/ \
Programmer Manager

---------------------------------

ObjectStructure
员工集合

结构图(文字版)

1
2
3
4
5
6
7
8
9
Visitor

ConcreteVisitor

Element

ConcreteElement

ObjectStructure

三、访问者模式核心原理

访问者模式依赖一个关键技术:

双分派(Double Dispatch)

普通Java只有 单分派

1
employee.accept(visitor);

访问者模式通过两次调用:

第一步

1
employee.accept(visitor)

第二步

1
visitor.visit(employee)

这样就能根据:

  • 访问者类型
  • 元素类型

执行不同逻辑。


四、完整代码示例(员工访问系统)

1 Visitor接口

1
2
3
4
5
6
7
interface Visitor {

void visit(Programmer programmer);

void visit(Manager manager);

}

2 Element接口

1
2
3
4
5
interface Employee {

void accept(Visitor visitor);

}

3 程序员类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Programmer implements Employee {

private int codeLines;

public Programmer(int codeLines) {
this.codeLines = codeLines;
}

public int getCodeLines() {
return codeLines;
}

@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

4 产品经理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Manager implements Employee {

private int products;

public Manager(int products) {
this.products = products;
}

public int getProducts() {
return products;
}

@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

5 CEO访问者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CEOVisitor implements Visitor {

@Override
public void visit(Programmer programmer) {

System.out.println(
"CEO查看程序员代码量:" + programmer.getCodeLines()
);

}

@Override
public void visit(Manager manager) {

System.out.println(
"CEO查看产品经理产品数:" + manager.getProducts()
);

}
}

6 CTO访问者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CTOVisitor implements Visitor {

@Override
public void visit(Programmer programmer) {

System.out.println(
"CTO查看程序员技术能力"
);

}

@Override
public void visit(Manager manager) {

System.out.println(
"CTO查看产品经理逻辑能力"
);

}
}

7 对象结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.*;

class Company {

private List<Employee> employees = new ArrayList<>();

public void add(Employee e) {
employees.add(e);
}

public void show(Visitor visitor) {

for (Employee e : employees) {
e.accept(visitor);
}

}
}

8 测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Test {

public static void main(String[] args) {

Company company = new Company();

company.add(new Programmer(10000));
company.add(new Manager(5));

System.out.println("CEO查看:");
company.show(new CEOVisitor());

System.out.println("---------------");

System.out.println("CTO查看:");
company.show(new CTOVisitor());
}

}

五、运行结果

1
2
3
4
5
6
7
8
CEO查看:
CEO查看程序员代码量:10000
CEO查看产品经理产品数:5

---------------
CTO查看:
CTO查看程序员技术能力
CTO查看产品经理逻辑能力

六、访问者模式优点

1 符合开闭原则

新增操作 → 只需要新增 Visitor

例如新增:

1
2
HRVisitor
FinanceVisitor

无需修改原有类。


2 职责清晰

操作逻辑集中在 Visitor 中。

1
2
Visitor = 行为
Element = 数据

3 易于扩展功能

新增统计方式:

1
2
3
绩效统计
薪资统计
代码统计

只需要新增访问者。

8.观察者模式

image-20260313171013681

观察者模式(Observer Pattern)是一种行为型设计模式
它定义了一种 一对多的依赖关系:当一个对象(被观察者 / Subject)状态发生变化时,所有依赖它的对象(观察者 / Observer)都会自动收到通知并更新。

简单理解一句话:

一个对象变化,自动通知一群依赖它的对象。

类似于消息推送中的推模式

生活中的例子

最经典的例子:订阅通知

比如:

  • 你关注了某个 UP 主
  • UP 主发视频
  • 所有关注者都会收到通知
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//观察者模式

//目标对象
public interface Subject {
void notifyObservers();
}

//真实目标对象
class ConcreteSubject implements Subject{

List<Observer> list=new ArrayList<>();

void add(Observer observer){
list.add(observer);
}

void remove(Observer observer){
list.remove(observer);
}

@Override
public void notifyObservers() {
System.out.println("目标改变通知其他观察者");
for (Observer observer : list) {
observer.response();
}
}
}

//观察者
interface Observer{
public void response();
}

//真实观察者
class Concrete1Observer implements Observer{

@Override
public void response() {
System.out.println("Concrete1观察者做出了相应反应");
}
}

class Concrete2Observer implements Observer{

@Override
public void response() {
System.out.println("Concrete2观察者做出了相应反应");
}
}

class Main3{
public static void main(String[] args) {
Observer observer1=new Concrete1Observer();
Observer observer2=new Concrete2Observer();

ConcreteSubject concreteSubject=new ConcreteSubject();
concreteSubject.add(observer1);
concreteSubject.add(observer2);
concreteSubject.notifyObservers();
}
}

9.解释器模式

image-20260313171024895

**解释器模式(Interpreter Pattern)**是一种 行为型设计模式,用于 定义一种语言的语法规则,并提供一个解释器来解释执行这种语言的句子

一句话理解:

解释器模式就是为一种简单语言构建一个“解释执行”的系统。

例如:

  • 数学表达式计算
  • SQL解析
  • 正则表达式
  • Spring SpEL
  • 编译器解析语法树

本质都是:

1
输入字符串 → 解析语法 → 执行含义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import java.util.HashMap;
import java.util.Map;

/**

* 解释器模式完整示例
*/
public class InterpreterPatternDemo {
/**
* 抽象表达式接口
* 定义所有表达式的解释方法
*/
interface Expression {
boolean interpret(Context context);
}

/**
* 上下文类
* 存储解释器运行时所需的数据环境
*/
static class Context {

private Map<String, Boolean> map = new HashMap<>();

public void put(String key, Boolean value) {
map.put(key, value);
}

public boolean get(String key) {
return map.get(key);
}
}

/**
* 终结符表达式
* 表示最基本的表达式并从Context中获取变量值
*/
static class VariableExpression implements Expression {

private String name;

public VariableExpression(String name) {
this.name = name;
}

@Override
public boolean interpret(Context context) {
return context.get(name);
}
}

/**
* 非终结符表达式
* 实现逻辑AND运算
*/
static class AndExpression implements Expression {

private Expression left;
private Expression right;

public AndExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}

@Override
public boolean interpret(Context context) {
return left.interpret(context) && right.interpret(context);
}
}

/**
* 非终结符表达式
* 实现逻辑OR运算
*/
static class OrExpression implements Expression {

private Expression left;
private Expression right;

public OrExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}

@Override
public boolean interpret(Context context) {
return left.interpret(context) || right.interpret(context);
}
}

/**
* 客户端
* 构建表达式并触发解释执行
*/
public static void main(String[] args) {

Context context = new Context();

context.put("A", true);
context.put("B", false);

Expression a = new VariableExpression("A");
Expression b = new VariableExpression("B");

Expression expression = new AndExpression(a, b);
boolean result = expression.interpret(context);

System.out.println("A AND B = " + result);
}
}

10.模板方法模式

image-20260313171037404

模板方法模式(Template Method)是一种行为型设计模式。它在抽象类中定义一个算法的骨架(模板方法),将某些步骤的实现延迟到子类中,从而允许子类在不改变算法结构的前提下重新定义算法的某些步骤。

在父类里面封装不可变的部分,在子类里面封装可变的部分,用于扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// 抽象类:定义算法骨架和必要的抽象/具体/钩子方法
abstract class AbstractProcessor {
// 模板方法:定义算法骨架的执行顺序
public final void templateMethod() {
stepOne();
stepTwo();
optionalStep();
hook();
}

// 基本操作:步骤一
protected abstract void stepOne();

// 基本操作:步骤二
protected abstract void stepTwo();

// 可选步骤:默认实现
protected void optionalStep() {
// 默认可空实现
}

// 钩子方法:子类可选择性扩展
protected void hook() {
// 默认可空实现
}
}

// 具体实现A:实现必须的步骤并扩展钩子
class ConcreteProcessorA extends AbstractProcessor {
// 实现步骤一
@Override
protected void stepOne() {
System.out.println("ConcreteProcessorA: stepOne");
}

// 实现步骤二
@Override
protected void stepTwo() {
System.out.println("ConcreteProcessorA: stepTwo");
}

// 重写钩子方法
@Override
protected void hook() {
System.out.println("ConcreteProcessorA: hook");
}
}

// 具体实现B:实现必须的步骤并改变可选步骤行为
class ConcreteProcessorB extends AbstractProcessor {
// 实现步骤一
@Override
protected void stepOne() {
System.out.println("ConcreteProcessorB: stepOne");
}

// 实现步骤二
@Override
protected void stepTwo() {
System.out.println("ConcreteProcessorB: stepTwo");
}

// 重写可选步骤
@Override
protected void optionalStep() {
System.out.println("ConcreteProcessorB: optionalStep");
}
}

// 演示类:执行模板方法
public class TemplateMethodDemo {
// 程序入口:演示模板方法在不同子类上的行为
public static void main(String[] args) {
AbstractProcessor a = new ConcreteProcessorA();
AbstractProcessor b = new ConcreteProcessorB();

System.out.println("Running ConcreteProcessorA:");
a.templateMethod();

System.out.println("\nRunning ConcreteProcessorB:");
b.templateMethod();
}
}

11.适配器模式

适配器模式是一种结构型设计模式
它的核心作用是:将一个类的接口转换成客户端期望的另一个接口,使原本由于接口不兼容而无法一起工作的类可以一起工作。

简单理解就是:

适配器 = 转换器

就像生活中的:

  • 手机充电转换头
  • 电源插头转换器
  • Type-C 转 USB

设备本身没问题,只是接口不一样,适配器负责把接口转换一下。

适配器模式的角色

适配器模式通常包含 4 个角色:

1 Target(目标接口)

客户端希望使用的接口

2 Adaptee(被适配者)

已经存在的类,但是接口不符合需求

3 Adapter(适配器)

负责把 Adaptee 的接口转换成 Target 接口

4 Client(客户端)

通过 Target 接口使用功能。

对象适配器结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 目标接口:客户端期望使用的播放接口
interface MediaPlayer {
// 播放媒体文件
void play(String fileName);
}

// 被适配者:旧系统中的播放器类
class Mp3Player {
// 播放MP3文件
public void playMp3(String fileName) {
System.out.println("Playing mp3 file: " + fileName);
}
}

// 适配器:将Mp3Player适配为MediaPlayer接口
class Mp3Adapter implements MediaPlayer {

// 被适配对象
private Mp3Player mp3Player;

// 构造方法:初始化被适配对象
public Mp3Adapter(Mp3Player mp3Player) {
this.mp3Player = mp3Player;
}

// 实现目标接口的方法
@Override
public void play(String fileName) {
mp3Player.playMp3(fileName);
}
}

// 客户端:通过目标接口调用功能
public class AdapterDemo {

// 程序入口:演示适配器模式的使用
public static void main(String[] args) {

// 创建被适配对象
Mp3Player mp3Player = new Mp3Player();

// 创建适配器对象
MediaPlayer player = new Mp3Adapter(mp3Player);

// 使用统一接口播放
player.play("music.mp3");
}
}

类适配器结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//适配器模式

public interface Target {
void request();
}

class Adapter{
void specificRequest(){

System.out.println("适配者中业务方法被调用");
};
}

class ClassAdapter extends Adapter implements Target{

@Override
public void request() {
specificRequest();
}
}

class Main5{
public static void main(String[] args) {
System.out.println("实现适配器");
Target target = new ClassAdapter();
target.request();
}
}

12.责任链模式

责任链模式是一种行为型设计模式
它的核心思想是:

将多个处理对象连成一条链,请求沿着这条链传递,直到有对象处理它为止。

这样可以让请求的发送者和接收者解耦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// 抽象处理者:定义处理请求的接口并保存下一个处理者
abstract class Handler {

// 下一个处理者
protected Handler nextHandler;

// 设置下一个处理者
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}

// 处理请求
public abstract void handleRequest(int days);
}

// 具体处理者:组长审批
class Leader extends Handler {

// 处理请假请求
@Override
public void handleRequest(int days) {
if (days <= 1) {
System.out.println("组长审批通过");
} else if (nextHandler != null) {
nextHandler.handleRequest(days);
}
}
}

// 具体处理者:经理审批
class Manager extends Handler {

// 处理请假请求
@Override
public void handleRequest(int days) {
if (days <= 3) {
System.out.println("经理审批通过");
} else if (nextHandler != null) {
nextHandler.handleRequest(days);
}
}
}

// 具体处理者:总监审批
class Director extends Handler {

// 处理请假请求
@Override
public void handleRequest(int days) {
if (days <= 7) {
System.out.println("总监审批通过");
} else {
System.out.println("请假天数过多,无法审批");
}
}
}

// 客户端:构建责任链并发起请求
public class ChainDemo {

// 程序入口
public static void main(String[] args) {

// 创建处理者
Handler leader = new Leader();
Handler manager = new Manager();
Handler director = new Director();

// 构建责任链
leader.setNextHandler(manager);
manager.setNextHandler(director);

// 发送请求
leader.handleRequest(5);
}
}