设计模式详解与Java实现
设计模式详解与Java实现
一、设计模式总览
1. 什么是设计模式
设计模式(Design Pattern)是软件开发中经过验证的、用于解决特定问题的最佳实践方案。它们是对软件设计中普遍存在的问题所提出的解决方案,是从许多优秀的软件系统中总结出来的成功经验。
设计模式的本质
设计模式不是代码,而是一种思想,一种解决问题的方法论。它描述了在特定场景下解决问题的通用方案。
2. GoF 23种设计模式简介
1994年,Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了《设计模式:可复用面向对象软件的基础》一书,书中收录了23种设计模式,这四人被称为 GoF(Gang of Four,四人组)。
3. 设计模式的三大分类
| 分类 | 包含模式数量 | 关注焦点 |
|---|---|---|
| 创建型模式 | 5种 | 对象的创建过程 |
| 结构型模式 | 7种 | 对象的组合方式 |
| 行为型模式 | 11种 | 对象之间的交互与职责分配 |
4. 学习设计模式的意义
- 提高代码复用性:设计模式提供了通用的解决方案,可以在多个项目中重复使用
- 提高可维护性:设计模式使代码结构更清晰,更易于理解和修改
- 提高扩展性:设计模式遵循开闭原则,使系统更容易扩展新功能
- 促进团队沟通:设计模式提供了共同的词汇,让团队成员更容易交流
- 提升设计能力:学习设计模式能帮助我们更好地理解面向对象设计原则
5. 设计模式原则(SOLID)
SOLID 原则
- S - Single Responsibility Principle(单一职责原则):一个类应该只有一个引起它变化的原因
- O - Open/Closed Principle(开闭原则):对扩展开放,对修改关闭
- L - Liskov Substitution Principle(里氏替换原则):子类应该能够替换父类并且不破坏原有功能
- I - Interface Segregation Principle(接口隔离原则):不应该强迫客户依赖它们不需要的方法
- D - Dependency Inversion Principle(依赖倒置原则):高层模块不应该依赖低层模块,都应该依赖抽象
二、创建型模式
创建型模式关注如何创建对象,将对象的创建与使用分离,使得系统更加灵活。
1. 单例模式(Singleton)
模式概述
单例模式确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。
解决的问题:当需要控制某个类的实例数量,或者需要一个全局唯一的访问点时使用。
使用场景:配置管理类、数据库连接池、日志记录器等。
模式结构
- Singleton:单例类,负责创建自己的唯一实例,并提供访问该实例的静态方法。
Java 实现案例
方式一:饿汉式(线程安全)
public class Singleton {
// 类加载时就创建实例
private static final Singleton instance = new Singleton();
// 私有构造方法,防止外部实例化
private Singleton() {}
// 提供全局访问点
public static Singleton getInstance() {
return instance;
}
}
方式二:懒汉式(双重检查锁定)
public class Singleton {
// volatile 保证多线程下的可见性和禁止指令重排序
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;
}
}
方式三:静态内部类(推荐)
public class Singleton {
private Singleton() {}
// 静态内部类,只有在第一次被引用时才会加载
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
方式四:枚举(最简洁)
public enum Singleton {
INSTANCE;
public void doSomething() {
System.out.println("Singleton doing something");
}
}
代码解析
- 饿汉式:简单安全,但在类加载时就创建,可能造成资源浪费
- 双重检查锁定:需要 volatile 关键字,实现较复杂但性能好
- 静态内部类:利用类加载机制保证线程安全,实现简单且延迟加载
- 枚举:最简单,由 JVM 保证线程安全和单一实例,还能防止反序列化
优缺点分析
优点:
- 控制实例数量,节省资源
- 提供全局访问点
- 避免对资源的多重占用
缺点:
- 违反单一职责原则,既负责创建自己又负责业务逻辑
- 扩展困难,没有抽象层
- 不适用于变化频繁的对象
实际应用场景
- JDK 中的应用:
java.lang.Runtime#getRuntime() - Spring 中的应用:Bean 默认作用域 singleton
2. 工厂方法模式(Factory Method)
模式概述
工厂方法模式定义一个创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
解决的问题:客户端不需要知道具体产品的创建细节,只需要知道对应的工厂即可。
使用场景:需要生成复杂对象,且对象类型可能经常变化的场景。
模式结构
- Product:抽象产品接口
- ConcreteProduct:具体产品实现
- Factory:抽象工厂接口
- ConcreteFactory:具体工厂实现
Java 实现案例
// 抽象产品
interface Product {
void use();
}
// 具体产品A
class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("使用产品A");
}
}
// 具体产品B
class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("使用产品B");
}
}
// 抽象工厂
interface Factory {
Product createProduct();
}
// 具体工厂A
class ConcreteFactoryA implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
// 具体工厂B
class ConcreteFactoryB implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Factory factory = new ConcreteFactoryA();
Product product = factory.createProduct();
product.use();
}
}
代码解析
- 抽象产品定义了产品的共同接口
- 每个具体产品对应一个具体工厂
- 客户端通过工厂创建产品,不需要知道具体产品类名
优缺点分析
优点:
- 符合开闭原则,增加新产品只需添加工厂类
- 客户端只需要知道抽象工厂,无须知道具体类
- 符合单一职责原则
缺点:
- 类的个数容易过多,增加系统复杂度
- 增加了系统的抽象性和理解难度
实际应用场景
- JDK 中的应用:
java.util.Collection#iterator() - Spring 中的应用:
BeanFactory
3. 抽象工厂模式(Abstract Factory)
模式概述
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
解决的问题:当需要创建一系列相关或相互依赖的对象时使用。
使用场景:GUI 工具包、数据库访问层等需要多系列产品的场景。
模式结构
- AbstractFactory:抽象工厂接口,声明创建多种产品的方法
- ConcreteFactory:具体工厂,实现创建具体产品的方法
- AbstractProduct:抽象产品接口
- ConcreteProduct:具体产品实现
Java 实现案例
// 抽象产品A
interface Button {
void paint();
}
// 具体产品A1
class WindowsButton implements Button {
@Override
public void paint() {
System.out.println("渲染Windows按钮");
}
}
// 具体产品A2
class MacButton implements Button {
@Override
public void paint() {
System.out.println("渲染Mac按钮");
}
}
// 抽象产品B
interface TextField {
void paint();
}
// 具体产品B1
class WindowsTextField implements TextField {
@Override
public void paint() {
System.out.println("渲染Windows文本框");
}
}
// 具体产品B2
class MacTextField implements TextField {
@Override
public void paint() {
System.out.println("渲染Mac文本框");
}
}
// 抽象工厂
interface GUIFactory {
Button createButton();
TextField createTextField();
}
// 具体工厂1
class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextField createTextField() {
return new WindowsTextField();
}
}
// 具体工厂2
class MacFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextField createTextField() {
return new MacTextField();
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
GUIFactory factory = new WindowsFactory();
Button button = factory.createButton();
TextField textField = factory.createTextField();
button.paint();
textField.paint();
}
}
代码解析
- 抽象工厂负责创建一个产品族(多个相关产品)
- 每个具体工厂创建同一系列的产品
- 确保同一工厂创建的产品相互兼容
优缺点分析
优点:
- 确保产品族中的产品相互兼容
- 避免客户端使用不兼容的产品
- 符合开闭原则
缺点:
- 难以支持新种类的产品,需要修改抽象工厂接口
- 增加了系统的抽象性和理解难度
实际应用场景
- JDK 中的应用:
java.sql.Connection接口 - Spring 中的应用:
ApplicationContext创建不同类型的 Bean
4. 建造者模式(Builder)
模式概述
建造者模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
解决的问题:当对象的创建过程复杂,且由多个部分组成时使用。
使用场景:构建复杂的配置对象、不可变对象等。
模式结构
- Product:产品(复杂对象)
- Builder:抽象建造者接口
- ConcreteBuilder:具体建造者
- Director:指挥者,负责调用建造者构建产品
Java 实现案例
方式一:经典建造者模式
// 产品类
class Computer {
private String cpu;
private String ram;
private String storage;
private String gpu;
public void setCpu(String cpu) { this.cpu = cpu; }
public void setRam(String ram) { this.ram = ram; }
public void setStorage(String storage) { this.storage = storage; }
public void setGpu(String gpu) { this.gpu = gpu; }
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", ram='" + ram + '\'' +
", storage='" + storage + '\'' +
", gpu='" + gpu + '\'' +
'}';
}
}
// 抽象建造者
interface ComputerBuilder {
void buildCpu();
void buildRam();
void buildStorage();
void buildGpu();
Computer getResult();
}
// 具体建造者 - 游戏本
class GamingComputerBuilder implements ComputerBuilder {
private Computer computer = new Computer();
@Override
public void buildCpu() { computer.setCpu("Intel i9"); }
@Override
public void buildRam() { computer.setRam("32GB"); }
@Override
public void buildStorage() { computer.setStorage("2TB SSD"); }
@Override
public void buildGpu() { computer.setGpu("RTX 4090"); }
@Override
public Computer getResult() { return computer; }
}
// 具体建造者 - 办公本
class OfficeComputerBuilder implements ComputerBuilder {
private Computer computer = new Computer();
@Override
public void buildCpu() { computer.setCpu("Intel i5"); }
@Override
public void buildRam() { computer.setRam("16GB"); }
@Override
public void buildStorage() { computer.setStorage("512GB SSD"); }
@Override
public void buildGpu() { computer.setGpu("集成显卡"); }
@Override
public Computer getResult() { return computer; }
}
// 指挥者
class Director {
public Computer construct(ComputerBuilder builder) {
builder.buildCpu();
builder.buildRam();
builder.buildStorage();
builder.buildGpu();
return builder.getResult();
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Director director = new Director();
ComputerBuilder builder = new GamingComputerBuilder();
Computer computer = director.construct(builder);
System.out.println(computer);
}
}
方式二:流式 Builder(更常用)
class User {
private final String name;
private final int age;
private final String email;
private final String phone;
private final String address;
private User(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.email = builder.email;
this.phone = builder.phone;
this.address = builder.address;
}
public static class Builder {
private String name;
private int age;
private String email;
private String phone;
private String address;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder email(String email) {
this.email = email;
return this;
}
public Builder phone(String phone) {
this.phone = phone;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public User build() {
return new User(this);
}
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", email='" + email + '\'' +
", phone='" + phone + '\'' +
", address='" + address + '\'' +
'}';
}
}
// 使用方式
public class Client {
public static void main(String[] args) {
User user = new User.Builder()
.name("张三")
.age(25)
.email("zhangsan@example.com")
.phone("13800138000")
.address("北京市")
.build();
System.out.println(user);
}
}
代码解析
- 经典模式将构建过程与表示分离,Director 负责控制构建流程
- 流式 Builder 更简洁,适合创建不可变对象
- 不需要记住所有参数,可以按需设置
优缺点分析
优点:
- 封装性好,构建过程与表示分离
- 扩展性好,易于添加新的产品表示
- 可以精细控制产品的构建过程
缺点:
- 产品内部变化复杂时,需要修改建造者类
- 增加了类的数量,可能使系统复杂
实际应用场景
- JDK 中的应用:
java.lang.StringBuilder、java.nio.ByteBuffer - Lombok 中的应用:
@Builder注解
5. 原型模式(Prototype)
模式概述
原型模式通过复制现有实例来创建新实例,而不需要通过 new 关键字创建。
解决的问题:当创建对象的代价较高时,可以通过复制原型来快速创建新对象。
使用场景:对象创建过程复杂但相似的场景,或者需要保护原始对象的场景。
模式结构
- Prototype:原型接口,声明克隆方法
- ConcretePrototype:具体原型类,实现克隆方法
- Client:客户端,通过克隆原型创建新对象
Java 实现案例
// 原型接口
interface Prototype extends Cloneable {
Prototype clone();
}
// 具体原型类
class Sheep implements Prototype {
private String name;
private int age;
private String color;
public Sheep(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getColor() { return color; }
public void setColor(String color) { this.color = color; }
@Override
public Sheep clone() {
try {
return (Sheep) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
'}';
}
}
// 深拷贝示例
class Address {
private String city;
private String street;
public Address(String city, String street) {
this.city = city;
this.street = street;
}
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public String getStreet() { return street; }
public void setStreet(String street) { this.street = street; }
@Override
public Address clone() {
return new Address(this.city, this.street);
}
}
class Person implements Prototype {
private String name;
private Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
public String getName() { return name; }
public Address getAddress() { return address; }
@Override
public Person clone() {
// 深拷贝
return new Person(this.name, this.address.clone());
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", address=" + address.getCity() + " " + address.getStreet() +
'}';
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
// 浅拷贝示例
Sheep original = new Sheep("多利", 3, "白色");
Sheep cloned = original.clone();
System.out.println("原型: " + original);
System.out.println("克隆: " + cloned);
System.out.println("是否同一对象: " + (original == cloned));
// 深拷贝示例
Address address = new Address("北京", "长安街");
Person person1 = new Person("张三", address);
Person person2 = person1.clone();
person2.getAddress().setCity("上海");
System.out.println("Person1: " + person1);
System.out.println("Person2: " + person2);
}
}
代码解析
- Java 中通过
Cloneable接口和clone()方法实现 - 浅拷贝只复制引用,深拷贝递归复制所有对象
- 深拷贝需要手动实现,或者通过序列化实现
优缺点分析
优点:
- 性能高,比直接 new 对象更快
- 简化对象创建过程
- 可以保护原始对象不被修改
缺点:
- 需要为每个类实现克隆方法
- 深拷贝实现复杂
- 需要处理循环引用问题
实际应用场景
- JDK 中的应用:
java.lang.Object#clone() - Spring 中的应用:Bean 的 scope="prototype"
三、结构型模式
结构型模式关注如何将类或对象组合成更大的结构,以实现新的功能。
1. 适配器模式(Adapter)
模式概述
适配器模式将一个类的接口转换成客户期望的另一个接口,使原本接口不兼容的类可以一起工作。
解决的问题:当需要使用一个已有的类,但其接口与需要的接口不匹配时使用。
使用场景:系统需要使用现有的类,而类的接口不符合系统需要。
模式结构
- Target:目标接口,客户期望的接口
- Adaptee:需要适配的类
- Adapter:适配器类,负责转换接口
Java 实现案例
方式一:类适配器(继承)
// 目标接口
interface Target {
void request();
}
// 被适配者
class Adaptee {
public void specificRequest() {
System.out.println("被适配者的特殊请求");
}
}
// 类适配器
class ClassAdapter extends Adaptee implements Target {
@Override
public void request() {
super.specificRequest();
}
}
方式二:对象适配器(组合)
// 目标接口
interface Target {
void request();
}
// 被适配者
class Adaptee {
public void specificRequest() {
System.out.println("被适配者的特殊请求");
}
}
// 对象适配器
class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
// 实际例子:USB 转 Type-C 适配器
// 旧接口:USB
interface USB {
void connectWithUSB();
}
class USBCharger implements USB {
@Override
public void connectWithUSB() {
System.out.println("连接 USB 充电");
}
}
// 新接口:Type-C
interface TypeC {
void connectWithTypeC();
}
class NewPhone implements TypeC {
@Override
public void connectWithTypeC() {
System.out.println("连接 Type-C 充电");
}
}
// 适配器
class USBToTypeCAdapter implements TypeC {
private USB usbCharger;
public USBToTypeCAdapter(USB usbCharger) {
this.usbCharger = usbCharger;
}
@Override
public void connectWithTypeC() {
System.out.println("适配器转换中...");
usbCharger.connectWithUSB();
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
USB oldCharger = new USBCharger();
TypeC adapter = new USBToTypeCAdapter(oldCharger);
adapter.connectWithTypeC();
}
}
代码解析
- 类适配器使用继承,对象适配器使用组合
- 对象适配器更灵活,可以适配多个被适配者
- 适配器负责接口转换,不改变原有功能
优缺点分析
优点:
- 提高了类的复用性
- 增加了类的透明度
- 灵活性好
缺点:
- 过多使用适配器会使系统复杂
- Java 不支持多重继承,类适配器有局限性
实际应用场景
- JDK 中的应用:
java.util.Arrays#asList()、java.io.InputStreamReader - Spring 中的应用:
AdvisorAdapter接口
2. 桥接模式(Bridge)
模式概述
桥接模式将抽象部分与实现部分分离,使它们都可以独立地变化。
解决的问题:当一个类存在两个或多个独立变化的维度时,使用桥接模式可以避免类爆炸。
使用场景:需要在抽象化和具体化之间增加更多灵活性的场景。
模式结构
- Abstraction:抽象类,定义抽象接口,持有实现部分的引用
- RefinedAbstraction:扩充抽象类
- Implementor:实现接口
- ConcreteImplementor:具体实现类
Java 实现案例
// 实现接口 - 颜色
interface Color {
void applyColor();
}
// 具体实现 - 红色
class RedColor implements Color {
@Override
public void applyColor() {
System.out.println("应用红色");
}
}
// 具体实现 - 蓝色
class BlueColor implements Color {
@Override
public void applyColor() {
System.out.println("应用蓝色");
}
}
// 抽象类 - 形状
abstract class Shape {
protected Color color;
public Shape(Color color) {
this.color = color;
}
public abstract void draw();
}
// 扩充抽象类 - 圆形
class Circle extends Shape {
public Circle(Color color) {
super(color);
}
@Override
public void draw() {
System.out.print("画圆形,");
color.applyColor();
}
}
// 扩充抽象类 - 矩形
class Rectangle extends Shape {
public Rectangle(Color color) {
super(color);
}
@Override
public void draw() {
System.out.print("画矩形,");
color.applyColor();
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Color red = new RedColor();
Color blue = new BlueColor();
Shape redCircle = new Circle(red);
Shape blueRectangle = new Rectangle(blue);
redCircle.draw();
blueRectangle.draw();
}
}
代码解析
- 抽象与实现分离,两者可以独立变化
- 通过组合而非继承来连接抽象和实现
- 避免了多层继承导致的类爆炸问题
优缺点分析
优点:
- 分离抽象和实现,提高可扩展性
- 符合开闭原则
- 实现细节对客户透明
缺点:
- 增加了系统的理解和设计难度
- 需要正确识别系统中两个独立变化的维度
实际应用场景
- JDK 中的应用:
java.sql.Driver接口 - AWT/Swing 中的应用:Component 和 ComponentPeer
3. 组合模式(Composite)
模式概述
组合模式将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
解决的问题:处理树形结构的对象时,统一对待叶子节点和分支节点。
使用场景:表示对象的部分-整体层次结构,如文件系统、菜单等。
模式结构
- Component:抽象构件,定义叶子和容器的共同接口
- Leaf:叶子节点,没有子节点
- Composite:容器节点,包含子节点
Java 实现案例
// 抽象构件
abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
public abstract void add(Component component);
public abstract void remove(Component component);
public abstract void display(int depth);
}
// 叶子节点
class Leaf extends Component {
public Leaf(String name) {
super(name);
}
@Override
public void add(Component component) {
System.out.println("叶子节点不能添加子节点");
}
@Override
public void remove(Component component) {
System.out.println("叶子节点不能删除子节点");
}
@Override
public void display(int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append("-");
}
System.out.println(sb + name);
}
}
// 容器节点
class Composite extends Component {
private List<Component> children = new ArrayList<>();
public Composite(String name) {
super(name);
}
@Override
public void add(Component component) {
children.add(component);
}
@Override
public void remove(Component component) {
children.remove(component);
}
@Override
public void display(int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append("-");
}
System.out.println(sb + name);
for (Component child : children) {
child.display(depth + 2);
}
}
}
// 实际例子:文件系统
abstract class FileSystemNode {
protected String name;
public FileSystemNode(String name) {
this.name = name;
}
public abstract void add(FileSystemNode node);
public abstract void remove(FileSystemNode node);
public abstract void display(int depth);
public abstract long getSize();
}
class File extends FileSystemNode {
private long size;
public File(String name, long size) {
super(name);
this.size = size;
}
@Override
public void add(FileSystemNode node) {
throw new UnsupportedOperationException("文件不能添加子节点");
}
@Override
public void remove(FileSystemNode node) {
throw new UnsupportedOperationException("文件不能删除子节点");
}
@Override
public void display(int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append(" ");
}
System.out.println(sb + "📄 " + name + " (" + size + " bytes)");
}
@Override
public long getSize() {
return size;
}
}
class Directory extends FileSystemNode {
private List<FileSystemNode> children = new ArrayList<>();
public Directory(String name) {
super(name);
}
@Override
public void add(FileSystemNode node) {
children.add(node);
}
@Override
public void remove(FileSystemNode node) {
children.remove(node);
}
@Override
public void display(int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append(" ");
}
System.out.println(sb + "📁 " + name);
for (FileSystemNode child : children) {
child.display(depth + 1);
}
}
@Override
public long getSize() {
long total = 0;
for (FileSystemNode child : children) {
total += child.getSize();
}
return total;
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Directory root = new Directory("根目录");
Directory docs = new Directory("文档");
Directory pics = new Directory("图片");
File file1 = new File("readme.txt", 1024);
File file2 = new File("notes.txt", 2048);
File pic1 = new File("photo.jpg", 10240);
docs.add(file1);
docs.add(file2);
pics.add(pic1);
root.add(docs);
root.add(pics);
root.display(0);
System.out.println("总大小: " + root.getSize() + " bytes");
}
}
代码解析
- 叶子节点和容器节点实现相同接口
- 客户端可以统一处理所有节点
- 递归调用实现树形结构遍历
优缺点分析
优点:
- 客户端可以一致地使用单个对象和组合对象
- 易于添加新构件
- 简化了客户端代码
缺点:
- 设计较复杂
- 可能使系统过于一般化
实际应用场景
- JDK 中的应用:
java.awt.Container和Component - XML DOM 中的应用:节点树结构
4. 装饰器模式(Decorator)
模式概述
装饰器模式动态地给一个对象添加额外的职责,比生成子类更灵活。
解决的问题:在不改变原有对象结构的情况下,动态地扩展对象的功能。
使用场景:需要动态地给对象添加功能,且这些功能可以动态撤销。
模式结构
- Component:抽象构件,定义接口
- ConcreteComponent:具体构件,需要被装饰的对象
- Decorator:抽象装饰器,持有构件引用
- ConcreteDecorator:具体装饰器,添加具体功能
Java 实现案例
// 抽象构件
interface Coffee {
double cost();
String description();
}
// 具体构件 - 简单咖啡
class SimpleCoffee implements Coffee {
@Override
public double cost() {
return 10.0;
}
@Override
public String description() {
return "简单咖啡";
}
}
// 抽象装饰器
abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
}
// 具体装饰器 - 加牛奶
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return coffee.cost() + 2.0;
}
@Override
public String description() {
return coffee.description() + " + 牛奶";
}
}
// 具体装饰器 - 加糖
class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return coffee.cost() + 1.0;
}
@Override
public String description() {
return coffee.description() + " + 糖";
}
}
// 具体装饰器 - 加奶泡
class WhipDecorator extends CoffeeDecorator {
public WhipDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return coffee.cost() + 3.0;
}
@Override
public String description() {
return coffee.description() + " + 奶泡";
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Coffee coffee = new SimpleCoffee();
System.out.println(coffee.description() + " 价格: " + coffee.cost());
// 加牛奶
coffee = new MilkDecorator(coffee);
System.out.println(coffee.description() + " 价格: " + coffee.cost());
// 再加糖
coffee = new SugarDecorator(coffee);
System.out.println(coffee.description() + " 价格: " + coffee.cost());
// 再加奶泡
coffee = new WhipDecorator(coffee);
System.out.println(coffee.description() + " 价格: " + coffee.cost());
}
}
代码解析
- 装饰器和被装饰对象实现相同接口
- 通过组合而非继承来扩展功能
- 可以动态添加多个装饰器,顺序也很重要
优缺点分析
优点:
- 比继承更灵活,不改变原有对象
- 可以动态添加和撤销功能
- 可以组合多个装饰器
缺点:
- 会产生很多小对象,增加系统复杂度
- 多层装饰会增加调试难度
实际应用场景
- JDK 中的应用:
java.io包中的流类(InputStream、OutputStream) - Spring 中的应用:
TransactionAwareCacheDecorator
5. 外观模式(Facade)
模式概述
外观模式为子系统中的一组接口提供一个统一的接口,定义了一个高层接口,使得子系统更容易使用。
解决的问题:简化复杂子系统的使用,提供统一入口。
使用场景:需要简化复杂系统的使用,或者需要屏蔽子系统的复杂性。
模式结构
- Facade:外观类,提供统一接口
- Subsystem:子系统类,实现具体功能
Java 实现案例
// 子系统类1 - 灯光控制
class Light {
public void on() {
System.out.println("打开灯光");
}
public void off() {
System.out.println("关闭灯光");
}
public void dim(int level) {
System.out.println("调节灯光亮度: " + level + "%");
}
}
// 子系统类2 - 音响控制
class Stereo {
public void on() {
System.out.println("打开音响");
}
public void off() {
System.out.println("关闭音响");
}
public void setVolume(int volume) {
System.out.println("调节音量: " + volume);
}
public void playCD() {
System.out.println("播放CD");
}
}
// 子系统类3 - 投影仪控制
class Projector {
public void on() {
System.out.println("打开投影仪");
}
public void off() {
System.out.println("关闭投影仪");
}
public void setInput(String input) {
System.out.println("切换输入源: " + input);
}
}
// 子系统类4 - 屏幕控制
class Screen {
public void down() {
System.out.println("放下屏幕");
}
public void up() {
System.out.println("收起屏幕");
}
}
// 外观类 - 家庭影院
class HomeTheaterFacade {
private Light light;
private Stereo stereo;
private Projector projector;
private Screen screen;
public HomeTheaterFacade(Light light, Stereo stereo,
Projector projector, Screen screen) {
this.light = light;
this.stereo = stereo;
this.projector = projector;
this.screen = screen;
}
public void watchMovie() {
System.out.println("======== 准备看电影 ========");
light.dim(10);
screen.down();
projector.on();
projector.setInput("DVD");
stereo.on();
stereo.setVolume(30);
stereo.playCD();
System.out.println("======== 开始观影 ========");
}
public void endMovie() {
System.out.println("======== 结束观影 ========");
light.dim(100);
screen.up();
projector.off();
stereo.off();
System.out.println("======== 影院关闭 ========");
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Light light = new Light();
Stereo stereo = new Stereo();
Projector projector = new Projector();
Screen screen = new Screen();
HomeTheaterFacade homeTheater = new HomeTheaterFacade(light, stereo, projector, screen);
// 客户端只需要调用简单的接口
homeTheater.watchMovie();
System.out.println();
homeTheater.endMovie();
}
}
代码解析
- 外观类封装复杂子系统,提供简单接口
- 客户端不需要知道子系统的细节
- 子系统类仍然可以被直接使用
优缺点分析
优点:
- 简化了客户端的使用
- 降低了客户端与子系统的耦合
- 子系统变化不会影响客户端
缺点:
- 可能不符合开闭原则,添加新功能需要修改外观类
- 可能成为上帝对象
实际应用场景
- JDK 中的应用:
java.lang.Class类 - Spring 中的应用:
JdbcTemplate、RestTemplate
6. 享元模式(Flyweight)
模式概述
享元模式运用共享技术有效地支持大量细粒度的对象。
解决的问题:当系统中存在大量相似对象时,通过共享来减少内存占用。
使用场景:系统中有大量相同或相似的对象,如文档编辑器中的字符、游戏中的树木等。
模式结构
- Flyweight:抽象享元,声明接口
- ConcreteFlyweight:具体享元,实现共享的状态
- UnsharedConcreteFlyweight:不可共享的享元
- FlyweightFactory:享元工厂,负责创建和管理享元对象
Java 实现案例
// 抽象享元
interface ChessPiece {
void display(int x, int y);
}
// 具体享元 - 棋子
class ConcreteChessPiece implements ChessPiece {
private String color; // 内部状态:颜色,可共享
public ConcreteChessPiece(String color) {
this.color = color;
}
@Override
public void display(int x, int y) { // x,y 是外部状态,不共享
System.out.println(color + "棋子在位置 (" + x + ", " + y + ")");
}
}
// 享元工厂
class ChessFactory {
private static Map<String, ChessPiece> chessPieces = new HashMap<>();
public static ChessPiece getChessPiece(String color) {
ChessPiece piece = chessPieces.get(color);
if (piece == null) {
piece = new ConcreteChessPiece(color);
chessPieces.put(color, piece);
System.out.println("创建新的" + color + "棋子");
}
return piece;
}
public static int getChessCount() {
return chessPieces.size();
}
}
// 实际例子:文字编辑器中的字符
// 享元类 - 字符
class Character {
private char value; // 内部状态:字符值
public Character(char value) {
this.value = value;
}
public void display(String font, int size) { // 外部状态:字体、大小
System.out.println("字符: '" + value + "', 字体: " + font + ", 大小: " + size);
}
}
// 享元工厂
class CharacterFactory {
private Map<Character, Character> characters = new HashMap<>();
public Character getCharacter(char c) {
Character character = characters.get(c);
if (character == null) {
character = new Character(c);
characters.put(c, character);
}
return character;
}
public int getCacheSize() {
return characters.size();
}
}
// 文档类
class Document {
private List<CharacterRun> runs = new ArrayList<>();
private CharacterFactory factory = new CharacterFactory();
public void addText(String text, String font, int size) {
for (char c : text.toCharArray()) {
Character character = factory.getCharacter(c);
runs.add(new CharacterRun(character, font, size));
}
}
public void display() {
for (CharacterRun run : runs) {
run.display();
}
System.out.println("缓存的字符数: " + factory.getCacheSize());
}
private static class CharacterRun {
private Character character;
private String font;
private int size;
public CharacterRun(Character character, String font, int size) {
this.character = character;
this.font = font;
this.size = size;
}
public void display() {
character.display(font, size);
}
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
System.out.println("===== 棋盘游戏示例 =====");
ChessPiece black1 = ChessFactory.getChessPiece("黑色");
ChessPiece black2 = ChessFactory.getChessPiece("黑色");
ChessPiece white1 = ChessFactory.getChessPiece("白色");
ChessPiece white2 = ChessFactory.getChessPiece("白色");
System.out.println("棋子对象数量: " + ChessFactory.getChessCount());
black1.display(1, 1);
black2.display(2, 3);
white1.display(5, 5);
white2.display(4, 2);
System.out.println("\n===== 文本编辑器示例 =====");
Document doc = new Document();
doc.addText("Hello World", "宋体", 12);
doc.addText("Hello Design Patterns", "黑体", 16);
doc.display();
}
}
代码解析
- 内部状态(可共享)存储在享元对象中
- 外部状态(不可共享)由客户端维护并传入
- 享元工厂负责管理享元对象池
优缺点分析
优点:
- 大幅减少对象数量,节省内存
- 外部状态相对独立,不影响内部状态
缺点:
- 使系统更复杂,需要分离内部和外部状态
- 可能引入线程安全问题
实际应用场景
- JDK 中的应用:
Integer.valueOf()、String常量池 - 数据库连接池
7. 代理模式(Proxy)
模式概述
代理模式为其他对象提供一种代理以控制对这个对象的访问。
解决的问题:在不改变原有对象的情况下,通过代理对象控制对原对象的访问。
使用场景:需要控制对对象的访问,如远程代理、虚拟代理、保护代理等。
模式结构
- Subject:抽象主题,定义代理和真实对象的共同接口
- RealSubject:真实主题,实际执行业务逻辑
- Proxy:代理主题,持有真实主题的引用,控制访问
Java 实现案例
方式一:静态代理
// 抽象主题
interface Image {
void display();
}
// 真实主题
class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("加载图片: " + fileName);
}
@Override
public void display() {
System.out.println("显示图片: " + fileName);
}
}
// 代理主题
class ImageProxy implements Image {
private RealImage realImage;
private String fileName;
public ImageProxy(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(fileName);
}
realImage.display();
}
}
方式二:JDK 动态代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 抽象主题
interface UserService {
void addUser(String name);
void deleteUser(String name);
}
// 真实主题
class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("添加用户: " + name);
}
@Override
public void deleteUser(String name) {
System.out.println("删除用户: " + name);
}
}
// 调用处理器
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("[日志] 方法 " + method.getName() + " 开始执行,参数: " +
(args != null ? Arrays.toString(args) : "无"));
long startTime = System.currentTimeMillis();
Object result = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println("[日志] 方法 " + method.getName() + " 执行完成,耗时: " +
(endTime - startTime) + "ms");
return result;
}
}
// 代理工厂
class ProxyFactory {
public static Object getProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new LogHandler(target)
);
}
}
方式三:CGLIB 代理(需要引入 CGLIB 库)
// CGLIB 通过继承实现代理,不需要接口
class OrderService {
public void createOrder(String orderId) {
System.out.println("创建订单: " + orderId);
}
}
// CGLIB 方法拦截器
class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
public Object getProxyInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("[CGLIB] 方法前处理");
Object result = proxy.invokeSuper(obj, args);
System.out.println("[CGLIB] 方法后处理");
return result;
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
System.out.println("===== 静态代理示例 =====");
Image image = new ImageProxy("test.jpg");
image.display(); // 第一次会加载
System.out.println();
image.display(); // 第二次直接显示
System.out.println("\n===== JDK 动态代理示例 =====");
UserService userService = new UserServiceImpl();
UserService proxy = (UserService) ProxyFactory.getProxy(userService);
proxy.addUser("张三");
System.out.println();
proxy.deleteUser("李四");
}
}
代码解析
- 静态代理需要为每个主题创建代理类
- JDK 动态代理基于接口,使用反射
- CGLIB 基于继承,不需要接口
优缺点分析
优点:
- 可以控制对真实对象的访问
- 不改变真实对象的代码
- 可以添加额外功能(日志、事务、安全等)
缺点:
- 增加了系统复杂度
- 可能会降低性能
实际应用场景
- Spring 中的应用:AOP 代理(JDK 动态代理或 CGLIB)
- MyBatis 中的应用:Mapper 接口的代理
- RMI:远程代理
四、行为型模式
行为型模式关注对象之间的通信和职责分配,描述对象之间如何协作完成任务。
1. 责任链模式(Chain of Responsibility)
模式概述
责任链模式使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
解决的问题:请求可能需要多个对象处理,但不知道具体哪个对象会处理。
使用场景:过滤器链、审批流程等。
模式结构
- Handler:抽象处理者,定义处理请求的接口
- ConcreteHandler:具体处理者,处理自己负责的请求
- Client:客户端,发起请求
Java 实现案例
// 抽象处理者
abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handleRequest(int request);
}
// 具体处理者A
class ConcreteHandlerA extends Handler {
@Override
public void handleRequest(int request) {
if (request < 10) {
System.out.println("HandlerA 处理请求: " + request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
// 具体处理者B
class ConcreteHandlerB extends Handler {
@Override
public void handleRequest(int request) {
if (request >= 10 && request < 20) {
System.out.println("HandlerB 处理请求: " + request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
// 具体处理者C
class ConcreteHandlerC extends Handler {
@Override
public void handleRequest(int request) {
if (request >= 20) {
System.out.println("HandlerC 处理请求: " + request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
// 实际例子:审批流程
class LeaveRequest {
private String name;
private int days;
private String reason;
public LeaveRequest(String name, int days, String reason) {
this.name = name;
this.days = days;
this.reason = reason;
}
public String getName() { return name; }
public int getDays() { return days; }
public String getReason() { return reason; }
}
abstract class Leader {
protected String name;
protected Leader nextLeader;
public Leader(String name) {
this.name = name;
}
public void setNextLeader(Leader nextLeader) {
this.nextLeader = nextLeader;
}
public abstract void handleRequest(LeaveRequest request);
}
class TeamLeader extends Leader {
public TeamLeader(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if (request.getDays() <= 2) {
System.out.println(name + "(组长)批准 " + request.getName() +
" 的请假,天数:" + request.getDays());
} else if (nextLeader != null) {
System.out.println(name + "(组长)无法处理,转交给上级");
nextLeader.handleRequest(request);
}
}
}
class DepartmentManager extends Leader {
public DepartmentManager(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if (request.getDays() <= 5) {
System.out.println(name + "(部门经理)批准 " + request.getName() +
" 的请假,天数:" + request.getDays());
} else if (nextLeader != null) {
System.out.println(name + "(部门经理)无法处理,转交给上级");
nextLeader.handleRequest(request);
}
}
}
class CEO extends Leader {
public CEO(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
System.out.println(name + "(CEO)批准 " + request.getName() +
" 的请假,天数:" + request.getDays());
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
System.out.println("===== 简单责任链示例 =====");
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
Handler handlerC = new ConcreteHandlerC();
handlerA.setNextHandler(handlerB);
handlerB.setNextHandler(handlerC);
int[] requests = {5, 15, 25};
for (int request : requests) {
handlerA.handleRequest(request);
}
System.out.println("\n===== 请假审批示例 =====");
Leader teamLeader = new TeamLeader("张三");
Leader deptManager = new DepartmentManager("李四");
Leader ceo = new CEO("王五");
teamLeader.setNextLeader(deptManager);
deptManager.setNextLeader(ceo);
LeaveRequest request1 = new LeaveRequest("小明", 1, "生病");
LeaveRequest request2 = new LeaveRequest("小红", 3, "旅游");
LeaveRequest request3 = new LeaveRequest("小刚", 10, "结婚");
teamLeader.handleRequest(request1);
System.out.println();
teamLeader.handleRequest(request2);
System.out.println();
teamLeader.handleRequest(request3);
}
}
代码解析
- 每个处理者持有下一个处理者的引用
- 请求沿着链条传递,直到被处理
- 客户端不需要知道具体的处理者
优缺点分析
优点:
- 降低发送者和接收者的耦合
- 可以动态地添加或修改处理者
- 符合单一职责原则
缺点:
- 请求可能不被处理
- 调试困难,可能会有循环调用
- 可能影响性能
实际应用场景
- Servlet 中的应用:
Filter过滤器链 - Spring 中的应用:拦截器链
- Netty 中的应用:ChannelPipeline
2. 命令模式(Command)
模式概述
命令模式将请求封装成对象,从而使你可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
解决的问题:将请求发送者和接收者解耦,支持撤销、重做等操作。
使用场景:需要撤销/重做操作、命令队列、日志记录等场景。
模式结构
- Command:命令接口,声明执行操作的方法
- ConcreteCommand:具体命令,绑定接收者和动作
- Receiver:接收者,执行实际操作
- Invoker:调用者,发起命令请求
- Client:客户端,创建命令并设置接收者
Java 实现案例
// 命令接口
interface Command {
void execute();
void undo();
}
// 接收者 - 电灯
class Light {
public void on() {
System.out.println("电灯打开");
}
public void off() {
System.out.println("电灯关闭");
}
}
// 具体命令 - 打开电灯
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
@Override
public void undo() {
light.off();
}
}
// 具体命令 - 关闭电灯
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.off();
}
@Override
public void undo() {
light.on();
}
}
// 接收者 - 风扇
class Fan {
public static final int HIGH = 3;
public static final int MEDIUM = 2;
public static final int LOW = 1;
public static final int OFF = 0;
private int speed;
public Fan() {
speed = OFF;
}
public void high() {
speed = HIGH;
System.out.println("风扇高速");
}
public void medium() {
speed = MEDIUM;
System.out.println("风扇中速");
}
public void low() {
speed = LOW;
System.out.println("风扇低速");
}
public void off() {
speed = OFF;
System.out.println("风扇关闭");
}
public int getSpeed() {
return speed;
}
}
// 具体命令 - 风扇高速
class FanHighCommand implements Command {
private Fan fan;
private int prevSpeed;
public FanHighCommand(Fan fan) {
this.fan = fan;
}
@Override
public void execute() {
prevSpeed = fan.getSpeed();
fan.high();
}
@Override
public void undo() {
if (prevSpeed == Fan.HIGH) {
fan.high();
} else if (prevSpeed == Fan.MEDIUM) {
fan.medium();
} else if (prevSpeed == Fan.LOW) {
fan.low();
} else {
fan.off();
}
}
}
// 调用者 - 遥控器
class RemoteControl {
private Command[] onCommands;
private Command[] offCommands;
private Command undoCommand;
public RemoteControl() {
onCommands = new Command[7];
offCommands = new Command[7];
Command noCommand = new NoCommand();
for (int i = 0; i < 7; i++) {
onCommands[i] = noCommand;
offCommands[i] = noCommand;
}
undoCommand = noCommand;
}
public void setCommand(int slot, Command onCommand, Command offCommand) {
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
public void onButtonWasPushed(int slot) {
onCommands[slot].execute();
undoCommand = onCommands[slot];
}
public void offButtonWasPushed(int slot) {
offCommands[slot].execute();
undoCommand = offCommands[slot];
}
public void undoButtonWasPushed() {
undoCommand.undo();
}
}
// 空命令
class NoCommand implements Command {
@Override
public void execute() {}
@Override
public void undo() {}
}
// 宏命令(一组命令)
class MacroCommand implements Command {
private Command[] commands;
public MacroCommand(Command[] commands) {
this.commands = commands;
}
@Override
public void execute() {
for (Command command : commands) {
command.execute();
}
}
@Override
public void undo() {
for (int i = commands.length - 1; i >= 0; i--) {
commands[i].undo();
}
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
System.out.println("===== 简单遥控器示例 =====");
RemoteControl remote = new RemoteControl();
Light light = new Light();
LightOnCommand lightOn = new LightOnCommand(light);
LightOffCommand lightOff = new LightOffCommand(light);
Fan fan = new Fan();
FanHighCommand fanHigh = new FanHighCommand(fan);
remote.setCommand(0, lightOn, lightOff);
remote.setCommand(1, fanHigh, new NoCommand());
remote.onButtonWasPushed(0);
remote.offButtonWasPushed(0);
remote.undoButtonWasPushed();
System.out.println();
remote.onButtonWasPushed(1);
remote.undoButtonWasPushed();
System.out.println("\n===== 宏命令示例 =====");
Command[] partyCommands = {lightOn, fanHigh};
MacroCommand partyMacro = new MacroCommand(partyCommands);
System.out.println("派对模式开始...");
partyMacro.execute();
System.out.println("撤销派对模式...");
partyMacro.undo();
}
}
代码解析
- 命令对象封装了接收者和动作
- 调用者通过命令对象间接调用接收者
- 可以支持撤销、重做、队列等操作
优缺点分析
优点:
- 降低调用者和接收者的耦合
- 易于添加新命令
- 支持撤销、重做、队列等
缺点:
- 可能产生大量命令类
实际应用场景
- JDK 中的应用:
Runnable接口 - Spring 中的应用:
JdbcTemplate中的回调 - UI 框架中的应用:按钮、菜单项的事件处理
3. 解释器模式(Interpreter)
模式概述
解释器模式给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解决的问题:对于特定类型的问题,构建一个简单的语言解释器。
使用场景:SQL解析、表达式求值、脚本语言等。
模式结构
- AbstractExpression:抽象表达式,声明解释操作
- TerminalExpression:终结符表达式
- NonterminalExpression:非终结符表达式
- Context:上下文,包含解释器之外的全局信息
- Client:客户端,构建抽象语法树
Java 实现案例
// 上下文
class Context {
private Map<String, Integer> variables = new HashMap<>();
public void setVariable(String name, int value) {
variables.put(name, value);
}
public int getVariable(String name) {
return variables.get(name);
}
}
// 抽象表达式
interface Expression {
int interpret(Context context);
}
// 终结符表达式 - 变量
class VariableExpression implements Expression {
private String name;
public VariableExpression(String name) {
this.name = name;
}
@Override
public int interpret(Context context) {
return context.getVariable(name);
}
}
// 终结符表达式 - 常量
class ConstantExpression implements Expression {
private int value;
public ConstantExpression(int value) {
this.value = value;
}
@Override
public int interpret(Context context) {
return value;
}
}
// 非终结符表达式 - 加法
class AddExpression implements Expression {
private Expression left;
private Expression right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) + right.interpret(context);
}
}
// 非终结符表达式 - 减法
class SubtractExpression implements Expression {
private Expression left;
private Expression right;
public SubtractExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) - right.interpret(context);
}
}
// 非终结符表达式 - 乘法
class MultiplyExpression implements Expression {
private Expression left;
private Expression right;
public MultiplyExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) * right.interpret(context);
}
}
// 计算器(简化的解析器)
class Calculator {
private Expression expression;
public void parse(String expression) {
Stack<Expression> stack = new Stack<>();
String[] tokens = expression.split(" ");
for (int i = 0; i < tokens.length; i++) {
String token = tokens[i];
if (token.equals("+")) {
Expression left = stack.pop();
Expression right = new VariableExpression(tokens[++i]);
stack.push(new AddExpression(left, right));
} else if (token.equals("-")) {
Expression left = stack.pop();
Expression right = new VariableExpression(tokens[++i]);
stack.push(new SubtractExpression(left, right));
} else if (token.equals("*")) {
Expression left = stack.pop();
Expression right = new VariableExpression(tokens[++i]);
stack.push(new MultiplyExpression(left, right));
} else {
stack.push(new VariableExpression(token));
}
}
this.expression = stack.pop();
}
public int calculate(Context context) {
return expression.interpret(context);
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
System.out.println("===== 手动构建表达式 =====");
// 计算: a + b - c
Context context = new Context();
context.setVariable("a", 10);
context.setVariable("b", 20);
context.setVariable("c", 5);
Expression a = new VariableExpression("a");
Expression b = new VariableExpression("b");
Expression c = new VariableExpression("c");
Expression add = new AddExpression(a, b);
Expression result = new SubtractExpression(add, c);
System.out.println("a + b - c = " + result.interpret(context));
System.out.println("\n===== 使用计算器 =====");
Calculator calculator = new Calculator();
calculator.parse("a b + c -"); // 后缀表达式
System.out.println("a + b - c = " + calculator.calculate(context));
}
}
代码解析
- 终结符表达式表示基本元素
- 非终结符表达式表示组合规则
- 上下文存储全局信息
优缺点分析
优点:
- 易于改变和扩展文法
- 易于实现简单的语言
缺点:
- 复杂文法难以维护
- 执行效率较低
实际应用场景
- JDK 中的应用:
java.util.regex.Pattern - SQL 解析器
- 表达式求值引擎
4. 迭代器模式(Iterator)
模式概述
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
解决的问题:统一遍历不同集合的方式,不暴露内部结构。
使用场景:需要遍历聚合对象,又不想暴露其内部表示。
模式结构
- Iterator:迭代器接口,定义访问和遍历元素的方法
- ConcreteIterator:具体迭代器,实现迭代器接口
- Aggregate:聚合接口,定义创建迭代器的方法
- ConcreteAggregate:具体聚合,实现创建迭代器的方法
Java 实现案例
// 迭代器接口
interface Iterator<T> {
boolean hasNext();
T next();
}
// 聚合接口
interface Aggregate<T> {
Iterator<T> createIterator();
}
// 具体聚合 - 书架
class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class BookShelf implements Aggregate<Book> {
private List<Book> books = new ArrayList<>();
public void addBook(Book book) {
books.add(book);
}
public Book getBookAt(int index) {
return books.get(index);
}
public int getLength() {
return books.size();
}
@Override
public Iterator<Book> createIterator() {
return new BookShelfIterator(this);
}
}
// 具体迭代器
class BookShelfIterator implements Iterator<Book> {
private BookShelf bookShelf;
private int index = 0;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
}
@Override
public boolean hasNext() {
return index < bookShelf.getLength();
}
@Override
public Book next() {
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
// 自定义集合迭代器示例
class MyList<T> implements Aggregate<T> {
private T[] items;
private int size = 0;
@SuppressWarnings("unchecked")
public MyList(int capacity) {
items = (T[]) new Object[capacity];
}
public void add(T item) {
if (size < items.length) {
items[size++] = item;
}
}
public T get(int index) {
return items[index];
}
public int size() {
return size;
}
@Override
public Iterator<T> createIterator() {
return new MyListIterator<>();
}
private class MyListIterator<E> implements Iterator<E> {
private int index = 0;
@Override
public boolean hasNext() {
return index < size;
}
@Override
@SuppressWarnings("unchecked")
public E next() {
return (E) items[index++];
}
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
System.out.println("===== 书架迭代器示例 =====");
BookShelf bookShelf = new BookShelf();
bookShelf.addBook(new Book("设计模式"));
bookShelf.addBook(new Book("Java编程思想"));
bookShelf.addBook(new Book("算法导论"));
Iterator<Book> iterator = bookShelf.createIterator();
while (iterator.hasNext()) {
Book book = iterator.next();
System.out.println("书名: " + book.getName());
}
System.out.println("\n===== 自定义列表示例 =====");
MyList<String> list = new MyList<>(5);
list.add("A");
list.add("B");
list.add("C");
Iterator<String> listIterator = list.createIterator();
while (listIterator.hasNext()) {
System.out.println("元素: " + listIterator.next());
}
System.out.println("\n===== Java 内置迭代器 =====");
List<String> javaList = Arrays.asList("X", "Y", "Z");
java.util.Iterator<String> javaIterator = javaList.iterator();
while (javaIterator.hasNext()) {
System.out.println("元素: " + javaIterator.next());
}
}
}
代码解析
- 迭代器负责遍历,聚合负责存储
- 客户端使用统一的迭代器接口
- 可以有多种遍历方式
优缺点分析
优点:
- 支持以不同方式遍历聚合
- 简化了聚合接口
- 可以同时进行多个遍历
缺点:
- 增加了类的数量
实际应用场景
- JDK 中的应用:
java.util.Iterator、java.lang.Iterable - Java 集合框架
5. 中介者模式(Mediator)
模式概述
中介者模式用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
解决的问题:多个对象之间存在复杂的交互关系,通过中介者解耦。
使用场景:GUI 组件交互、聊天室、MVC 中的 Controller 等。
模式结构
- Mediator:抽象中介者,定义同事对象通信的接口
- ConcreteMediator:具体中介者,协调各同事对象
- Colleague:抽象同事类,持有中介者引用
- ConcreteColleague:具体同事类
Java 实现案例
// 抽象中介者
interface Mediator {
void send(String message, Colleague colleague);
}
// 抽象同事类
abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
}
// 具体同事类A
class ConcreteColleagueA extends Colleague {
public ConcreteColleagueA(Mediator mediator) {
super(mediator);
}
public void send(String message) {
mediator.send(message, this);
}
public void receive(String message) {
System.out.println("同事A收到消息: " + message);
}
}
// 具体同事类B
class ConcreteColleagueB extends Colleague {
public ConcreteColleagueB(Mediator mediator) {
super(mediator);
}
public void send(String message) {
mediator.send(message, this);
}
public void receive(String message) {
System.out.println("同事B收到消息: " + message);
}
}
// 具体中介者
class ConcreteMediator implements Mediator {
private ConcreteColleagueA colleagueA;
private ConcreteColleagueB colleagueB;
public void setColleagueA(ConcreteColleagueA colleagueA) {
this.colleagueA = colleagueA;
}
public void setColleagueB(ConcreteColleagueB colleagueB) {
this.colleagueB = colleagueB;
}
@Override
public void send(String message, Colleague colleague) {
if (colleague == colleagueA) {
colleagueB.receive(message);
} else if (colleague == colleagueB) {
colleagueA.receive(message);
}
}
}
// 实际例子:聊天室
class User {
private String name;
private ChatRoom chatRoom;
public User(String name, ChatRoom chatRoom) {
this.name = name;
this.chatRoom = chatRoom;
}
public String getName() {
return name;
}
public void send(String message) {
chatRoom.sendMessage(message, this);
}
public void receive(String message, User sender) {
System.out.println(name + " 收到 " + sender.getName() + " 的消息: " + message);
}
}
class ChatRoom {
private List<User> users = new ArrayList<>();
public void join(User user) {
users.add(user);
System.out.println(user.getName() + " 加入聊天室");
}
public void sendMessage(String message, User sender) {
for (User user : users) {
if (user != sender) {
user.receive(message, sender);
}
}
}
}
// 实际例子:MVC 简化示例
class Model {
private String data;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
class View {
public void display(String data) {
System.out.println("视图显示: " + data);
}
public String getUserInput() {
return "用户输入的数据";
}
}
class Controller {
private Model model;
private View view;
public Controller(Model model, View view) {
this.model = model;
this.view = view;
}
public void handleInput() {
String input = view.getUserInput();
model.setData(input);
updateView();
}
public void updateView() {
view.display(model.getData());
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
System.out.println("===== 简单中介者示例 =====");
ConcreteMediator mediator = new ConcreteMediator();
ConcreteColleagueA a = new ConcreteColleagueA(mediator);
ConcreteColleagueB b = new ConcreteColleagueB(mediator);
mediator.setColleagueA(a);
mediator.setColleagueB(b);
a.send("你好,我是A");
b.send("你好,我是B");
System.out.println("\n===== 聊天室示例 =====");
ChatRoom room = new ChatRoom();
User alice = new User("Alice", room);
User bob = new User("Bob", room);
User charlie = new User("Charlie", room);
room.join(alice);
room.join(bob);
room.join(charlie);
System.out.println();
alice.send("大家好!");
System.out.println();
bob.send("你好!");
System.out.println("\n===== MVC 示例 =====");
Model model = new Model();
View view = new View();
Controller controller = new Controller(model, view);
controller.handleInput();
}
}
代码解析
- 同事对象之间通过中介者通信
- 中介者封装了对象之间的交互逻辑
- 同事对象不需要知道其他同事的存在
优缺点分析
优点:
- 减少了对象之间的耦合
- 将对象协作集中管理
- 简化了对象之间的交互
缺点:
- 中介者可能变得复杂
- 可能成为上帝对象
实际应用场景
- JDK 中的应用:
java.util.Timer - Swing 中的应用:ButtonGroup
- MVC 模式中的 Controller
6. 备忘录模式(Memento)
模式概述
备忘录模式在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。
解决的问题:需要保存对象的某个状态以便在需要时恢复。
使用场景:撤销操作、游戏存档、数据库事务等。
模式结构
- Originator:原发器,创建备忘录并恢复状态
- Memento:备忘录,存储原发器的状态
- Caretaker:负责人,保存备忘录但不修改它
Java 实现案例
// 备忘录类
class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// 原发器
class Originator {
private String state;
public void setState(String state) {
this.state = state;
System.out.println("设置状态: " + state);
}
public String getState() {
return state;
}
public Memento saveStateToMemento() {
System.out.println("保存状态到备忘录");
return new Memento(state);
}
public void getStateFromMemento(Memento memento) {
state = memento.getState();
System.out.println("从备忘录恢复状态: " + state);
}
}
// 负责人
class Caretaker {
private List<Memento> mementoList = new ArrayList<>();
public void add(Memento state) {
mementoList.add(state);
}
public Memento get(int index) {
return mementoList.get(index);
}
public Memento getLast() {
if (!mementoList.isEmpty()) {
return mementoList.get(mementoList.size() - 1);
}
return null;
}
}
// 实际例子:编辑器撤销
class TextEditor {
private StringBuilder content = new StringBuilder();
public void type(String text) {
content.append(text);
}
public String getContent() {
return content.toString();
}
public EditorMemento save() {
System.out.println("保存内容: " + content);
return new EditorMemento(content.toString());
}
public void restore(EditorMemento memento) {
content = new StringBuilder(memento.getContent());
System.out.println("恢复内容: " + content);
}
}
class EditorMemento {
private String content;
public EditorMemento(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
class History {
private Stack<EditorMemento> history = new Stack<>();
public void push(EditorMemento memento) {
history.push(memento);
}
public EditorMemento pop() {
if (!history.isEmpty()) {
return history.pop();
}
return null;
}
}
// 实际例子:游戏存档
class GameState {
private int level;
private int score;
private String health;
public GameState(int level, int score, String health) {
this.level = level;
this.score = score;
this.health = health;
}
public int getLevel() { return level; }
public int getScore() { return score; }
public String getHealth() { return health; }
}
class Game {
private int level = 1;
private int score = 0;
private String health = "100%";
public void play() {
level++;
score += 100;
health = (100 - level * 10) + "%";
System.out.println("游戏进行中 - 关卡: " + level + ", 分数: " + score + ", 生命: " + health);
}
public GameMemento save() {
System.out.println("游戏存档");
return new GameMemento(new GameState(level, score, health));
}
public void load(GameMemento memento) {
GameState state = memento.getState();
this.level = state.getLevel();
this.score = state.getScore();
this.health = state.getHealth();
System.out.println("游戏读档 - 关卡: " + level + ", 分数: " + score + ", 生命: " + health);
}
}
class GameMemento {
private GameState state;
public GameMemento(GameState state) {
this.state = state;
}
public GameState getState() {
return state;
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
System.out.println("===== 简单备忘录示例 =====");
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("State #1");
originator.setState("State #2");
caretaker.add(originator.saveStateToMemento());
originator.setState("State #3");
caretaker.add(originator.saveStateToMemento());
originator.setState("State #4");
System.out.println("当前状态: " + originator.getState());
originator.getStateFromMemento(caretaker.get(0));
System.out.println("恢复到第一次保存的状态: " + originator.getState());
originator.getStateFromMemento(caretaker.get(1));
System.out.println("恢复到第二次保存的状态: " + originator.getState());
System.out.println("\n===== 编辑器撤销示例 =====");
TextEditor editor = new TextEditor();
History history = new History();
editor.type("Hello ");
history.push(editor.save());
editor.type("World!");
history.push(editor.save());
editor.type(" How are you?");
System.out.println("当前内容: " + editor.getContent());
editor.restore(history.pop());
System.out.println("撤销一次: " + editor.getContent());
editor.restore(history.pop());
System.out.println("撤销两次: " + editor.getContent());
System.out.println("\n===== 游戏存档示例 =====");
Game game = new Game();
List<GameMemento> saves = new ArrayList<>();
game.play();
saves.add(game.save());
game.play();
game.play();
saves.add(game.save());
game.play();
System.out.println();
game.load(saves.get(1));
game.load(saves.get(0));
}
}
代码解析
- 备忘录存储原发器的状态,只有原发器可以访问
- 负责人保存备忘录,但不修改其内容
- 可以保存多个状态点,实现多次撤销
优缺点分析
优点:
- 保持封装边界
- 简化了原发器
- 可以实现撤销和恢复
缺点:
- 可能消耗大量内存
- 备忘录的维护有成本
实际应用场景
- JDK 中的应用:
java.util.Date(可通过 setTime 恢复) - 编辑器的撤销操作
- 数据库事务的回滚
7. 观察者模式(Observer)
模式概述
观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
解决的问题:一个对象状态变化需要通知其他对象,且不希望紧耦合。
使用场景:事件处理、消息通知、MVC 中的 Model 和 View 等。
模式结构
- Subject:主题,管理观察者并发送通知
- ConcreteSubject:具体主题,保存状态
- Observer:观察者,定义更新接口
- ConcreteObserver:具体观察者,实现更新
Java 实现案例
// 观察者接口
interface Observer {
void update(String message);
}
// 主题接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体主题
class NewsAgency implements Subject {
private List<Observer> observers = new ArrayList<>();
private String news;
public void setNews(String news) {
this.news = news;
notifyObservers();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(news);
}
}
}
// 具体观察者
class NewsChannel implements Observer {
private String name;
private String news;
public NewsChannel(String name) {
this.name = name;
}
@Override
public void update(String news) {
this.news = news;
display();
}
public void display() {
System.out.println(name + " 播报新闻: " + news);
}
}
// Java 内置观察者模式
class WeatherData extends java.util.Observable {
private float temperature;
private float humidity;
private float pressure;
public void measurementsChanged() {
setChanged();
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
public float getTemperature() { return temperature; }
public float getHumidity() { return humidity; }
public float getPressure() { return pressure; }
}
class CurrentConditionsDisplay implements java.util.Observer {
private float temperature;
private float humidity;
public CurrentConditionsDisplay(java.util.Observable observable) {
observable.addObserver(this);
}
@Override
public void update(java.util.Observable o, Object arg) {
if (o instanceof WeatherData) {
WeatherData weatherData = (WeatherData) o;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
public void display() {
System.out.println("当前条件: " + temperature + "度, " + humidity + "%湿度");
}
}
// 事件监听器示例
class Event {
private String type;
private Object source;
public Event(String type, Object source) {
this.type = type;
this.source = source;
}
public String getType() { return type; }
public Object getSource() { return source; }
}
interface EventListener {
void onEvent(Event event);
}
class Button {
private List<EventListener> listeners = new ArrayList<>();
public void addListener(EventListener listener) {
listeners.add(listener);
}
public void click() {
System.out.println("按钮被点击");
Event event = new Event("click", this);
for (EventListener listener : listeners) {
listener.onEvent(event);
}
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
System.out.println("===== 新闻订阅示例 =====");
NewsAgency agency = new NewsAgency();
NewsChannel channel1 = new NewsChannel("新闻频道1");
NewsChannel channel2 = new NewsChannel("新闻频道2");
agency.registerObserver(channel1);
agency.registerObserver(channel2);
agency.setNews("第一条新闻: 今天天气晴朗");
System.out.println();
agency.removeObserver(channel1);
agency.setNews("第二条新闻: 明天有雨");
System.out.println("\n===== Java 内置观察者示例 =====");
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay display = new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(25, 65, 1013);
weatherData.setMeasurements(28, 70, 1010);
System.out.println("\n===== 事件监听器示例 =====");
Button button = new Button();
button.addListener(event -> System.out.println("监听器1: " + event.getType() + " 事件"));
button.addListener(event -> System.out.println("监听器2: 记录日志"));
button.click();
}
}
代码解析
- 主题管理观察者列表
- 状态变化时通知所有观察者
- 观察者可以随时注册和注销
优缺点分析
优点:
- 主题和观察者之间松耦合
- 支持广播通信
- 符合开闭原则
缺点:
- 通知顺序不确定
- 可能有循环依赖
- 可能导致意外的更新
实际应用场景
- JDK 中的应用:
java.util.Observer、java.util.Observable - Swing 中的应用:事件监听器
- Spring 中的应用:
ApplicationEvent、ApplicationListener
8. 状态模式(State)
模式概述
状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
解决的问题:对象的行为依赖于它的状态,并且可以根据状态改变而改变。
使用场景:状态机、订单状态、游戏角色状态等。
模式结构
- Context:上下文,维护当前状态
- State:状态接口,定义行为
- ConcreteState:具体状态,实现对应行为
Java 实现案例
// 状态接口
interface State {
void handle(Context context);
}
// 上下文
class Context {
private State state;
public Context() {
state = null;
}
public void setState(State state) {
this.state = state;
}
public State getState() {
return state;
}
public void request() {
state.handle(this);
}
}
// 具体状态A
class ConcreteStateA implements State {
@Override
public void handle(Context context) {
System.out.println("当前状态: A");
context.setState(new ConcreteStateB());
}
}
// 具体状态B
class ConcreteStateB implements State {
@Override
public void handle(Context context) {
System.out.println("当前状态: B");
context.setState(new ConcreteStateA());
}
}
// 实际例子:电梯状态
interface ElevatorState {
void openDoor();
void closeDoor();
void move();
void stop();
}
class OpenState implements ElevatorState {
private Elevator elevator;
public OpenState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void openDoor() {
System.out.println("门已经打开了");
}
@Override
public void closeDoor() {
System.out.println("关闭门");
elevator.setState(elevator.getCloseState());
}
@Override
public void move() {
System.out.println("门打开着,不能移动");
}
@Override
public void stop() {
System.out.println("已经停止了");
}
}
class CloseState implements ElevatorState {
private Elevator elevator;
public CloseState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void openDoor() {
System.out.println("打开门");
elevator.setState(elevator.getOpenState());
}
@Override
public void closeDoor() {
System.out.println("门已经关闭了");
}
@Override
public void move() {
System.out.println("电梯开始运行");
elevator.setState(elevator.getRunState());
}
@Override
public void stop() {
System.out.println("已经停止了");
}
}
class RunState implements ElevatorState {
private Elevator elevator;
public RunState(Elevator elevator) {
this.elevator = elevator;
}
@Override
public void openDoor() {
System.out.println("电梯运行中,不能开门");
}
@Override
public void closeDoor() {
System.out.println("门已经关闭了");
}
@Override
public void move() {
System.out.println("电梯正在运行");
}
@Override
public void stop() {
System.out.println("电梯停止");
elevator.setState(elevator.getCloseState());
}
}
class Elevator {
private ElevatorState openState;
private ElevatorState closeState;
private ElevatorState runState;
private ElevatorState currentState;
public Elevator() {
openState = new OpenState(this);
closeState = new CloseState(this);
runState = new RunState(this);
currentState = closeState;
}
public void setState(ElevatorState state) {
currentState = state;
}
public ElevatorState getOpenState() { return openState; }
public ElevatorState getCloseState() { return closeState; }
public ElevatorState getRunState() { return runState; }
public void openDoor() { currentState.openDoor(); }
public void closeDoor() { currentState.closeDoor(); }
public void move() { currentState.move(); }
public void stop() { currentState.stop(); }
}
// 实际例子:订单状态
enum OrderStatus {
NEW, PAID, SHIPPED, DELIVERED, CANCELLED
}
interface OrderState {
void pay(Order order);
void ship(Order order);
void deliver(Order order);
void cancel(Order order);
OrderStatus getStatus();
}
class NewState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("订单已支付");
order.setState(new PaidState());
}
@Override
public void ship(Order order) {
System.out.println("订单未支付,不能发货");
}
@Override
public void deliver(Order order) {
System.out.println("订单未发货,不能签收");
}
@Override
public void cancel(Order order) {
System.out.println("订单已取消");
order.setState(new CancelledState());
}
@Override
public OrderStatus getStatus() {
return OrderStatus.NEW;
}
}
class PaidState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("订单已支付,无需重复支付");
}
@Override
public void ship(Order order) {
System.out.println("订单已发货");
order.setState(new ShippedState());
}
@Override
public void deliver(Order order) {
System.out.println("订单未发货,不能签收");
}
@Override
public void cancel(Order order) {
System.out.println("订单已取消,退款中...");
order.setState(new CancelledState());
}
@Override
public OrderStatus getStatus() {
return OrderStatus.PAID;
}
}
class ShippedState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("订单已支付");
}
@Override
public void ship(Order order) {
System.out.println("订单已发货");
}
@Override
public void deliver(Order order) {
System.out.println("订单已签收");
order.setState(new DeliveredState());
}
@Override
public void cancel(Order order) {
System.out.println("订单已发货,不能取消");
}
@Override
public OrderStatus getStatus() {
return OrderStatus.SHIPPED;
}
}
class DeliveredState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("订单已支付");
}
@Override
public void ship(Order order) {
System.out.println("订单已签收");
}
@Override
public void deliver(Order order) {
System.out.println("订单已签收");
}
@Override
public void cancel(Order order) {
System.out.println("订单已签收,不能取消");
}
@Override
public OrderStatus getStatus() {
return OrderStatus.DELIVERED;
}
}
class CancelledState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("订单已取消");
}
@Override
public void ship(Order order) {
System.out.println("订单已取消");
}
@Override
public void deliver(Order order) {
System.out.println("订单已取消");
}
@Override
public void cancel(Order order) {
System.out.println("订单已取消");
}
@Override
public OrderStatus getStatus() {
return OrderStatus.CANCELLED;
}
}
class Order {
private String id;
private OrderState state;
public Order(String id) {
this.id = id;
this.state = new NewState();
}
public void setState(OrderState state) {
this.state = state;
}
public void pay() { state.pay(this); }
public void ship() { state.ship(this); }
public void deliver() { state.deliver(this); }
public void cancel() { state.cancel(this); }
public OrderStatus getStatus() { return state.getStatus(); }
}
// 客户端使用
public class Client {
public static void main(String[] args) {
System.out.println("===== 简单状态转换 =====");
Context context = new Context();
context.setState(new ConcreteStateA());
context.request();
context.request();
context.request();
System.out.println("\n===== 电梯状态示例 =====");
Elevator elevator = new Elevator();
elevator.openDoor();
elevator.move();
elevator.closeDoor();
elevator.move();
elevator.openDoor();
elevator.stop();
elevator.closeDoor();
elevator.stop();
System.out.println("\n===== 订单状态示例 =====");
Order order = new Order("12345");
System.out.println("当前状态: " + order.getStatus());
order.ship();
order.pay();
System.out.println("当前状态: " + order.getStatus());
order.ship();
System.out.println("当前状态: " + order.getStatus());
order.deliver();
System.out.println("当前状态: " + order.getStatus());
order.cancel();
}
}
代码解析
- 每个状态类封装该状态下的行为
- 上下文维护当前状态并委托请求
- 状态转换可以由状态类或上下文控制
优缺点分析
优点:
- 封装了状态转换规则
- 避免了大量的条件语句
- 状态相关的代码集中在一个类中
缺点:
- 会增加类的数量
- 状态转换可能变得复杂
实际应用场景
- JDK 中的应用:
java.util.Iterator(隐含状态) - Spring 中的应用:
StateMachine(状态机) - 工作流引擎
9. 策略模式(Strategy)
模式概述
策略模式定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
解决的问题:需要在多种算法中选择一种,并且可以灵活替换。
使用场景:排序策略、支付方式、折扣策略等。
模式结构
- Strategy:策略接口,定义算法
- ConcreteStrategy:具体策略,实现算法
- Context:上下文,使用策略
Java 实现案例
// 策略接口
interface Strategy {
int doOperation(int num1, int num2);
}
// 具体策略A - 加法
class OperationAdd implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
// 具体策略B - 减法
class OperationSubtract implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
// 具体策略C - 乘法
class OperationMultiply implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
// 上下文
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2) {
return strategy.doOperation(num1, num2);
}
}
// 实际例子:排序策略
interface SortStrategy {
void sort(int[] array);
}
class BubbleSort implements SortStrategy {
@Override
public void sort(int[] array) {
System.out.println("使用冒泡排序");
int n = array.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (array[j] > array[j + 1]) {
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
}
class QuickSort implements SortStrategy {
@Override
public void sort(int[] array) {
System.out.println("使用快速排序");
quickSort(array, 0, array.length - 1);
}
private void quickSort(int[] array, int low, int high) {
if (low < high) {
int pi = partition(array, low, high);
quickSort(array, low, pi - 1);
quickSort(array, pi + 1, high);
}
}
private int partition(int[] array, int low, int high) {
int pivot = array[high];
int i = (low - 1);
for (int j = low; j < high; j++) {
if (array[j] < pivot) {
i++;
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
int temp = array[i + 1];
array[i + 1] = array[high];
array[high] = temp;
return i + 1;
}
}
class Sorter {
private SortStrategy strategy;
public Sorter(SortStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(SortStrategy strategy) {
this.strategy = strategy;
}
public void sort(int[] array) {
strategy.sort(array);
}
}
// 实际例子:支付策略
interface PaymentStrategy {
void pay(double amount);
}
class Alipay implements PaymentStrategy {
private String email;
public Alipay(String email) {
this.email = email;
}
@Override
public void pay(double amount) {
System.out.println("支付宝支付: " + amount + " 元, 账号: " + email);
}
}
class WeChatPay implements PaymentStrategy {
private String phone;
public WeChatPay(String phone) {
this.phone = phone;
}
@Override
public void pay(double amount) {
System.out.println("微信支付: " + amount + " 元, 账号: " + phone);
}
}
class CreditCard implements PaymentStrategy {
private String cardNumber;
private String cvv;
private String expiryDate;
public CreditCard(String cardNumber, String cvv, String expiryDate) {
this.cardNumber = cardNumber;
this.cvv = cvv;
this.expiryDate = expiryDate;
}
@Override
public void pay(double amount) {
System.out.println("信用卡支付: " + amount + " 元, 卡号: " + cardNumber);
}
}
class ShoppingCart {
private List<Item> items = new ArrayList<>();
public void addItem(Item item) {
items.add(item);
}
public void removeItem(Item item) {
items.remove(item);
}
public double calculateTotal() {
return items.stream().mapToDouble(Item::getPrice).sum();
}
public void pay(PaymentStrategy paymentMethod) {
double amount = calculateTotal();
paymentMethod.pay(amount);
}
}
class Item {
private String name;
private double price;
public Item(String name, double price) {
this.name = name;
this.price = price;
}
public double getPrice() {
return price;
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
System.out.println("===== 简单计算策略 =====");
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context.setStrategy(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context.setStrategy(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
System.out.println("\n===== 排序策略示例 =====");
int[] array = {64, 34, 25, 12, 22, 11, 90};
Sorter sorter = new Sorter(new BubbleSort());
sorter.sort(array);
System.out.println("排序结果: " + Arrays.toString(array));
int[] array2 = {64, 34, 25, 12, 22, 11, 90};
sorter.setStrategy(new QuickSort());
sorter.sort(array2);
System.out.println("排序结果: " + Arrays.toString(array2));
System.out.println("\n===== 支付策略示例 =====");
ShoppingCart cart = new ShoppingCart();
cart.addItem(new Item("书籍", 100));
cart.addItem(new Item("文具", 50));
cart.pay(new Alipay("user@example.com"));
System.out.println();
cart.pay(new WeChatPay("13800138000"));
System.out.println();
cart.pay(new CreditCard("1234-5678-9012-3456", "123", "12/25"));
}
}
代码解析
- 策略封装算法实现
- 上下文使用策略但不了解细节
- 策略可以在运行时动态切换
优缺点分析
优点:
- 算法可以自由切换
- 避免多重条件判断
- 扩展性好
缺点:
- 策略类会增多
- 客户端需要了解策略
实际应用场景
- JDK 中的应用:
Comparator接口 - Spring 中的应用:
Resource接口 - 支付系统
10. 模板方法模式(Template Method)
模式概述
模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
解决的问题:算法的整体结构固定,但某些步骤的实现可以变化。
使用场景:有固定流程但具体步骤实现不同的场景。
模式结构
- AbstractClass:抽象类,定义模板方法和抽象操作
- ConcreteClass:具体类,实现抽象操作
Java 实现案例
// 抽象类
abstract class AbstractClass {
// 模板方法 - 定义算法骨架
public final void templateMethod() {
primitiveOperation1();
primitiveOperation2();
hook();
concreteOperation();
}
// 基本方法 - 抽象方法,由子类实现
protected abstract void primitiveOperation1();
protected abstract void primitiveOperation2();
// 基本方法 - 钩子方法,子类可以选择覆盖
protected void hook() {}
// 基本方法 - 具体方法,已经实现
private void concreteOperation() {
System.out.println("执行具体操作");
}
}
// 具体类A
class ConcreteClassA extends AbstractClass {
@Override
protected void primitiveOperation1() {
System.out.println("具体类A实现的操作1");
}
@Override
protected void primitiveOperation2() {
System.out.println("具体类A实现的操作2");
}
}
// 具体类B
class ConcreteClassB extends AbstractClass {
@Override
protected void primitiveOperation1() {
System.out.println("具体类B实现的操作1");
}
@Override
protected void primitiveOperation2() {
System.out.println("具体类B实现的操作2");
}
@Override
protected void hook() {
System.out.println("具体类B覆盖的钩子方法");
}
}
// 实际例子:冲泡饮料
abstract class Beverage {
// 模板方法
public final void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
}
private void boilWater() {
System.out.println("把水煮沸");
}
protected abstract void brew();
private void pourInCup() {
System.out.println("倒入杯中");
}
protected abstract void addCondiments();
// 钩子方法 - 子类可以覆盖
protected boolean customerWantsCondiments() {
return true;
}
}
class Tea extends Beverage {
@Override
protected void brew() {
System.out.println("浸泡茶叶");
}
@Override
protected void addCondiments() {
System.out.println("加入柠檬");
}
}
class Coffee extends Beverage {
@Override
protected void brew() {
System.out.println("冲泡咖啡");
}
@Override
protected void addCondiments() {
System.out.println("加入糖和牛奶");
}
@Override
protected boolean customerWantsCondiments() {
// 可以根据用户输入决定是否加调料
return Math.random() > 0.5;
}
}
// 实际例子:游戏角色创建
abstract class Character {
public final void create() {
chooseRace();
chooseClass();
customizeAppearance();
equipStartingGear();
startGame();
}
protected abstract void chooseRace();
protected abstract void chooseClass();
protected abstract void customizeAppearance();
protected void equipStartingGear() {
System.out.println("装备初始武器");
}
protected void startGame() {
System.out.println("开始游戏!");
}
}
class Warrior extends Character {
@Override
protected void chooseRace() {
System.out.println("选择人类");
}
@Override
protected void chooseClass() {
System.out.println("选择战士");
}
@Override
protected void customizeAppearance() {
System.out.println("设置强壮的外观");
}
@Override
protected void equipStartingGear() {
System.out.println("装备剑和盾牌");
}
}
class Mage extends Character {
@Override
protected void chooseRace() {
System.out.println("选择精灵");
}
@Override
protected void chooseClass() {
System.out.println("选择法师");
}
@Override
protected void customizeAppearance() {
System.out.println("设置神秘的外观");
}
@Override
protected void equipStartingGear() {
System.out.println("装备法杖和魔法书");
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
System.out.println("===== 简单模板方法示例 =====");
AbstractClass classA = new ConcreteClassA();
classA.templateMethod();
System.out.println();
AbstractClass classB = new ConcreteClassB();
classB.templateMethod();
System.out.println("\n===== 冲泡饮料示例 =====");
Beverage tea = new Tea();
tea.prepareRecipe();
System.out.println();
Beverage coffee = new Coffee();
coffee.prepareRecipe();
System.out.println("\n===== 游戏角色示例 =====");
Character warrior = new Warrior();
warrior.create();
System.out.println();
Character mage = new Mage();
mage.create();
}
}
代码解析
- 模板方法定义算法的骨架(通常是 final)
- 抽象方法由子类实现具体步骤
- 钩子方法提供额外的扩展点
优缺点分析
优点:
- 代码复用,提取公共代码到父类
- 反向控制,父类控制流程,子类实现细节
- 符合开闭原则
缺点:
- 类的数量增加
- 算法骨架难以修改
实际应用场景
- JDK 中的应用:
InputStream、OutputStream、AbstractList - Servlet 中的应用:
HttpServlet - JUnit 中的应用:
TestCase
11. 访问者模式(Visitor)
模式概述
访问者模式表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
解决的问题:需要对对象结构中的元素进行多种不同操作,且操作可能变化。
使用场景:对象结构稳定但操作易变,如编译器、文档处理等。
模式结构
- Visitor:访问者接口,为每个具体元素定义访问方法
- ConcreteVisitor:具体访问者,实现访问方法
- Element:元素接口,定义接受访问者的方法
- ConcreteElement:具体元素,实现 accept 方法
- ObjectStructure:对象结构,管理元素集合
Java 实现案例
// 访问者接口
interface Visitor {
void visit(ConcreteElementA element);
void visit(ConcreteElementB element);
}
// 具体访问者A
class ConcreteVisitorA implements Visitor {
@Override
public void visit(ConcreteElementA element) {
System.out.println("访问者A访问元素A: " + element.operationA());
}
@Override
public void visit(ConcreteElementB element) {
System.out.println("访问者A访问元素B: " + element.operationB());
}
}
// 具体访问者B
class ConcreteVisitorB implements Visitor {
@Override
public void visit(ConcreteElementA element) {
System.out.println("访问者B访问元素A: " + element.operationA());
}
@Override
public void visit(ConcreteElementB element) {
System.out.println("访问者B访问元素B: " + element.operationB());
}
}
// 元素接口
interface Element {
void accept(Visitor visitor);
}
// 具体元素A
class ConcreteElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operationA() {
return "元素A的操作";
}
}
// 具体元素B
class ConcreteElementB implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operationB() {
return "元素B的操作";
}
}
// 对象结构
class ObjectStructure {
private List<Element> elements = new ArrayList<>();
public void attach(Element element) {
elements.add(element);
}
public void detach(Element element) {
elements.remove(element);
}
public void accept(Visitor visitor) {
for (Element element : elements) {
element.accept(visitor);
}
}
}
// 实际例子:文件系统访问者
interface FileSystemVisitor {
void visit(File file);
void visit(Directory directory);
}
abstract class FileSystemElement {
protected String name;
public FileSystemElement(String name) {
this.name = name;
}
public abstract void accept(FileSystemVisitor visitor);
}
class File extends FileSystemElement {
private int size;
public File(String name, int size) {
super(name);
this.size = size;
}
public int getSize() {
return size;
}
@Override
public void accept(FileSystemVisitor visitor) {
visitor.visit(this);
}
}
class Directory extends FileSystemElement {
private List<FileSystemElement> children = new ArrayList<>();
public Directory(String name) {
super(name);
}
public void add(FileSystemElement element) {
children.add(element);
}
public List<FileSystemElement> getChildren() {
return children;
}
@Override
public void accept(FileSystemVisitor visitor) {
visitor.visit(this);
}
}
class SizeCalculator implements FileSystemVisitor {
private int totalSize = 0;
@Override
public void visit(File file) {
System.out.println("计算文件大小: " + file.name + " (" + file.getSize() + " bytes)");
totalSize += file.getSize();
}
@Override
public void visit(Directory directory) {
System.out.println("进入目录: " + directory.name);
for (FileSystemElement child : directory.getChildren()) {
child.accept(this);
}
}
public int getTotalSize() {
return totalSize;
}
}
class FilePrinter implements FileSystemVisitor {
private int depth = 0;
@Override
public void visit(File file) {
printIndent();
System.out.println("📄 " + file.name);
}
@Override
public void visit(Directory directory) {
printIndent();
System.out.println("📁 " + directory.name);
depth++;
for (FileSystemElement child : directory.getChildren()) {
child.accept(this);
}
depth--;
}
private void printIndent() {
for (int i = 0; i < depth; i++) {
System.out.print(" ");
}
}
}
// 实际例子:XML 元素访问者
interface XmlVisitor {
void visit(XmlElement element);
void visit(XmlText text);
}
abstract class XmlNode {
public abstract void accept(XmlVisitor visitor);
}
class XmlElement extends XmlNode {
private String name;
private Map<String, String> attributes = new HashMap<>();
private List<XmlNode> children = new ArrayList<>();
public XmlElement(String name) {
this.name = name;
}
public void setAttribute(String name, String value) {
attributes.put(name, value);
}
public void addChild(XmlNode child) {
children.add(child);
}
public String getName() { return name; }
public Map<String, String> getAttributes() { return attributes; }
public List<XmlNode> getChildren() { return children; }
@Override
public void accept(XmlVisitor visitor) {
visitor.visit(this);
}
}
class XmlText extends XmlNode {
private String text;
public XmlText(String text) {
this.text = text;
}
public String getText() { return text; }
@Override
public void accept(XmlVisitor visitor) {
visitor.visit(this);
}
}
class XmlPrinter implements XmlVisitor {
private int depth = 0;
@Override
public void visit(XmlElement element) {
printIndent();
System.out.print("<" + element.getName());
for (Map.Entry<String, String> attr : element.getAttributes().entrySet()) {
System.out.print(" " + attr.getKey() + "=\"" + attr.getValue() + "\"");
}
System.out.println(">");
depth++;
for (XmlNode child : element.getChildren()) {
child.accept(this);
}
depth--;
printIndent();
System.out.println("</" + element.getName() + ">");
}
@Override
public void visit(XmlText text) {
printIndent();
System.out.println(text.getText());
}
private void printIndent() {
for (int i = 0; i < depth; i++) {
System.out.print(" ");
}
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
System.out.println("===== 简单访问者示例 =====");
ObjectStructure structure = new ObjectStructure();
structure.attach(new ConcreteElementA());
structure.attach(new ConcreteElementB());
Visitor visitorA = new ConcreteVisitorA();
structure.accept(visitorA);
System.out.println();
Visitor visitorB = new ConcreteVisitorB();
structure.accept(visitorB);
System.out.println("\n===== 文件系统访问者示例 =====");
Directory root = new Directory("根目录");
Directory docs = new Directory("文档");
docs.add(new File("readme.txt", 1024));
docs.add(new File("notes.txt", 2048));
root.add(docs);
root.add(new File("photo.jpg", 10240));
FilePrinter printer = new FilePrinter();
root.accept(printer);
System.out.println();
SizeCalculator calculator = new SizeCalculator();
root.accept(calculator);
System.out.println("总大小: " + calculator.getTotalSize() + " bytes");
System.out.println("\n===== XML 访问者示例 =====");
XmlElement html = new XmlElement("html");
XmlElement body = new XmlElement("body");
XmlElement div = new XmlElement("div");
div.setAttribute("class", "container");
div.addChild(new XmlText("Hello World!"));
body.addChild(div);
html.addChild(body);
XmlPrinter xmlPrinter = new XmlPrinter();
html.accept(xmlPrinter);
}
}
代码解析
- 访问者为每个元素类型定义访问方法
- 元素通过 accept 方法接受访问者
- 双重分派实现正确的方法调用
优缺点分析
优点:
- 易于添加新的访问者(操作)
- 相关行为集中在访问者中
- 可以跨越类层次结构进行操作
缺点:
- 添加新元素困难,需要修改所有访问者
- 可能破坏封装性
实际应用场景
- JDK 中的应用:
javax.lang.model.element.ElementVisitor - 编译器中的应用:AST 遍历
- XML/HTML 文档处理
五、设计模式总结
1. 设计模式分类回顾
| 分类 | 模式名称 |
|---|---|
| 创建型模式 (5种) | 单例、工厂方法、抽象工厂、建造者、原型 |
| 结构型模式 (7种) | 适配器、桥接、组合、装饰器、外观、享元、代理 |
| 行为型模式 (11种) | 责任链、命令、解释器、迭代器、中介者、备忘录、观察者、状态、策略、模板方法、访问者 |
2. 设计模式选择指南
| 问题场景 | 推荐模式 |
|---|---|
| 需要唯一实例 | 单例模式 |
| 需要创建复杂对象 | 建造者模式 |
| 需要复制对象 | 原型模式 |
| 需要动态添加功能 | 装饰器模式 |
| 需要统一访问方式 | 适配器模式 |
| 需要树形结构 | 组合模式 |
| 需要简化接口 | 外观模式 |
| 需要一对多通知 | 观察者模式 |
| 需要状态驱动行为 | 状态模式 |
| 需要算法可切换 | 策略模式 |
| 需要流程固定 | 模板方法模式 |
| 需要命令封装 | 命令模式 |
| 需要撤销功能 | 命令模式 + 备忘录模式 |
3. 学习建议
- 理解原则:先理解 SOLID 原则,这是设计模式的基础
- 循序渐进:先学习常用模式(单例、工厂、观察者、策略、装饰器等)
- 结合实践:在实际项目中尝试使用,理解模式的适用场景
- 不要过度设计:模式是工具,不是目的,避免为了使用模式而使用模式
- 阅读源码:学习框架中设计模式的实际应用
4. 设计模式在开源框架中的应用
| 框架 | 应用的设计模式 |
|---|---|
| Spring | 单例、工厂、代理、模板方法、观察者、策略、适配器 |
| MyBatis | 工厂、代理、模板方法、装饰器 |
| Netty | 责任链、观察者、策略 |
| JDK | 迭代器、观察者、命令、适配器、装饰器、模板方法 |
参考资料:
- 《设计模式:可复用面向对象软件的基础》- GoF
- 《Head First 设计模式》
- 《Java 设计模式》