前言
设计模式是解决特定问题的成熟方案。分为三大类:创建型(怎么造对象)、结构型(怎么组合对象)、行为型(对象间怎么协作)。
一、创建型模式(5种)
1. 单例模式 (Singleton)
需求场景:系统需要一个全局的配置管理器,要求:
- 整个应用只有一个配置实例
- 任何地方都能访问到同一份配置
- 避免重复创建造成资源浪费
为什么用单例而不是其他方案?
- ❌ 静态类:无法实现接口,难以扩展和测试
- ❌ 全局变量:不安全,可能被意外修改
- ✅ 单例模式:既保证唯一性,又保持面向对象特性
class ConfigManager {
private static ConfigManager instance;
private Properties config;
private ConfigManager() {
config = new Properties();
// 加载配置文件
}
public static ConfigManager getInstance() {
if (instance == null) {
instance = new ConfigManager();
}
return instance;
}
public String getProperty(String key) {
return config.getProperty(key);
}
}
// 使用 - 全局访问同一实例
ConfigManager.getInstance().getProperty("database.url");
ConfigManager.getInstance().getProperty("app.name");
核心价值:保证全局唯一实例,统一访问点
2. 工厂方法模式 (Factory Method)
需求场景:开发一个日志系统,需要支持多种日志输出方式(文件、数据库、控制台),要求:
- 根据配置动态选择日志输出方式
- 新增日志类型时不修改现有代码
- 客户端不需要知道具体日志类的实现
为什么用工厂方法而不是直接new?
- ❌ 直接new:客户端与具体类耦合,难以扩展
- ❌ 简单if-else:新增类型需要修改现有代码
- ✅ 工厂方法:每种产品有专门工厂,符合开闭原则
// 产品接口
interface Logger {
void log(String message);
}
// 具体产品
class FileLogger implements Logger {
public void log(String message) {
System.out.println("[文件] " + message);
}
}
class DatabaseLogger implements Logger {
public void log(String message) {
System.out.println("[数据库] " + message);
}
}
// 工厂接口
abstract class LoggerFactory {
abstract Logger createLogger();
}
// 具体工厂 - 每个工厂专门创建一种产品
class FileLoggerFactory extends LoggerFactory {
Logger createLogger() { return new FileLogger(); }
}
class DatabaseLoggerFactory extends LoggerFactory {
Logger createLogger() { return new DatabaseLogger(); }
}
// 客户端 - 根据配置选择工厂
String logType = "file"; // 来自配置文件
LoggerFactory factory = "file".equals(logType) ?
new FileLoggerFactory() : new DatabaseLoggerFactory();
Logger logger = factory.createLogger();
logger.log("系统启动");
核心价值:每种产品有专门工厂,便于扩展新产品
3. 抽象工厂模式 (Abstract Factory)
需求场景:开发跨平台UI应用,需要为不同操作系统创建一套风格一致的UI组件,要求:
- 确保同一平台的组件风格统一
- 切换平台时整套组件都要切换
- 新增平台支持时不影响现有代码
为什么用抽象工厂而不是工厂方法?
- ❌ 工厂方法:只能保证单个产品的创建,无法保证产品间的一致性
- ❌ 直接创建:容易出现Windows按钮配Mac输入框的情况
- ✅ 抽象工厂:确保创建的是同一系列的产品
// 产品接口
interface Button { void render(); }
interface TextBox { void display(); }
// Windows系列产品
class WinButton implements Button {
public void render() { System.out.println("Windows风格按钮"); }
}
class WinTextBox implements TextBox {
public void display() { System.out.println("Windows风格输入框"); }
}
// Mac系列产品
class MacButton implements Button {
public void render() { System.out.println("Mac风格按钮"); }
}
class MacTextBox implements TextBox {
public void display() { System.out.println("Mac风格输入框"); }
}
// 抽象工厂 - 创建一系列相关产品
interface UIFactory {
Button createButton();
TextBox createTextBox();
}
// 具体工厂 - 保证创建的产品风格一致
class WindowsFactory implements UIFactory {
public Button createButton() { return new WinButton(); }
public TextBox createTextBox() { return new WinTextBox(); }
}
class MacFactory implements UIFactory {
public Button createButton() { return new MacButton(); }
public TextBox createTextBox() { return new MacTextBox(); }
}
// 使用 - 一次性创建整套组件
String os = System.getProperty("os.name");
UIFactory factory = os.contains("Windows") ?
new WindowsFactory() : new MacFactory();
Button btn = factory.createButton();
TextBox text = factory.createTextBox();
// 确保风格一致
核心价值:创建一系列相关产品,保证产品间的兼容性
4. 建造者模式 (Builder)
需求场景:构建SQL查询语句,需要支持复杂的查询条件组合,要求:
- 参数很多且大部分可选
- 构建过程要清晰易读
- 支持链式调用提高代码可读性
为什么用建造者而不是构造函数?
- ❌ 多个构造函数:参数过多时容易出错,可读性差
- ❌ setXxx方法:对象可能处于不完整状态
- ✅ 建造者模式:分步构建,参数含义清晰
class SqlQuery {
private String select;
private String from;
private String where;
private String orderBy;
private int limit;
private SqlQuery() {}
public static class Builder {
private SqlQuery query = new SqlQuery();
public Builder select(String fields) {
query.select = fields;
return this;
}
public Builder from(String table) {
query.from = table;
return this;
}
public Builder where(String condition) {
query.where = condition;
return this;
}
public Builder orderBy(String field) {
query.orderBy = field;
return this;
}
public Builder limit(int count) {
query.limit = count;
return this;
}
public SqlQuery build() {
if (query.select == null || query.from == null) {
throw new IllegalStateException("SELECT和FROM是必需的");
}
return query;
}
}
@Override
public String toString() {
StringBuilder sql = new StringBuilder();
sql.append("SELECT ").append(select)
.append(" FROM ").append(from);
if (where != null) sql.append(" WHERE ").append(where);
if (orderBy != null) sql.append(" ORDER BY ").append(orderBy);
if (limit > 0) sql.append(" LIMIT ").append(limit);
return sql.toString();
}
}
// 使用 - 清晰的链式构建
SqlQuery query = new SqlQuery.Builder()
.select("name, age")
.from("users")
.where("age > 18")
.orderBy("name")
.limit(10)
.build();
System.out.println(query); // SELECT name, age FROM users WHERE age > 18 ORDER BY name LIMIT 10
核心价值:分步构建复杂对象,提高代码可读性
5. 原型模式 (Prototype)
需求场景:游戏中需要创建大量相似的敌人,每个敌人的基础属性相同,但位置不同,要求:
- 避免重复的复杂初始化过程
- 快速创建大量相似对象
- 支持深拷贝避免属性共享问题
为什么用原型而不是直接new?
- ❌ 直接new:每次都要重复复杂的初始化逻辑
- ❌ 工厂方法:仍然需要重复创建过程
- ✅ 原型模式:通过复制避免重复初始化,性能更好
class Enemy implements Cloneable {
private String type;
private int health;
private Position position;
private List<String> skills;
public Enemy(String type) {
this.type = type;
// 复杂的初始化过程
initializeStats();
loadSkills();
}
private void initializeStats() {
// 从数据库或配置文件加载属性
this.health = 100;
}
private void loadSkills() {
// 加载技能列表
this.skills = Arrays.asList("攻击", "防御");
}
@Override
public Enemy clone() {
try {
Enemy cloned = (Enemy) super.clone();
// 深拷贝
cloned.position = new Position(position.x, position.y);
cloned.skills = new ArrayList<>(skills);
return cloned;
} catch (CloneNotSupportedException e) {
return null;
}
}
public void setPosition(int x, int y) {
this.position = new Position(x, y);
}
}
// 使用 - 快速创建多个敌人
Enemy zombiePrototype = new Enemy("僵尸"); // 复杂初始化只执行一次
// 通过克隆快速创建
Enemy zombie1 = zombiePrototype.clone();
zombie1.setPosition(10, 20);
Enemy zombie2 = zombiePrototype.clone();
zombie2.setPosition(30, 40);
核心价值:通过复制避免重复的复杂对象创建过程
二、结构型模式(7种)
6. 适配器模式 (Adapter)
需求场景:系统需要集成第三方支付SDK,但第三方接口与系统现有接口不兼容,要求:
- 不修改第三方SDK代码
- 不修改现有系统接口
- 让不兼容的接口能够协同工作
为什么用适配器而不是直接修改?
- ❌ 修改第三方代码:版本升级时会丢失修改
- ❌ 修改现有接口:影响其他已有实现
- ✅ 适配器模式:在中间做转换,不影响双方
// 系统现有的支付接口
interface PaymentProcessor {
boolean processPayment(String userId, double amount);
}
// 第三方支付SDK(不能修改)
class ThirdPartyPayment {
public String makePayment(String account, String money, String currency) {
System.out.println("第三方支付:账户" + account + " 金额" + money + currency);
return "SUCCESS";
}
}
// 适配器 - 转换接口调用
class PaymentAdapter implements PaymentProcessor {
private ThirdPartyPayment thirdPartyPayment;
public PaymentAdapter(ThirdPartyPayment thirdPartyPayment) {
this.thirdPartyPayment = thirdPartyPayment;
}
@Override
public boolean processPayment(String userId, double amount) {
// 接口转换:系统接口 -> 第三方接口
String account = "USER_" + userId;
String money = String.valueOf(amount);
String result = thirdPartyPayment.makePayment(account, money, "CNY");
return "SUCCESS".equals(result);
}
}
// 使用 - 统一的接口调用
PaymentProcessor processor = new PaymentAdapter(new ThirdPartyPayment());
boolean success = processor.processPayment("12345", 99.9);
核心价值:让不兼容的接口能够协同工作
7. 装饰器模式 (Decorator)
需求场景:开发一个文本处理系统,需要对文本进行多种格式化处理(加密、压缩、编码),要求:
- 可以任意组合不同的处理方式
- 动态添加或移除处理功能
- 不修改原始文本类的代码
为什么用装饰器而不是继承?
- ❌ 继承:需要为每种组合创建子类(类爆炸问题)
- ❌ 修改原类:违反开闭原则,影响现有功能
- ✅ 装饰器模式:像穿衣服一样层层包装,灵活组合
// 核心接口
interface TextProcessor {
String process(String text);
}
// 基础实现
class PlainText implements TextProcessor {
public String process(String text) {
return text;
}
}
// 装饰器基类
abstract class TextDecorator implements TextProcessor {
protected TextProcessor processor;
public TextDecorator(TextProcessor processor) {
this.processor = processor;
}
}
// 具体装饰器
class EncryptDecorator extends TextDecorator {
public EncryptDecorator(TextProcessor processor) {
super(processor);
}
public String process(String text) {
String result = processor.process(text);
return "[加密]" + new StringBuilder(result).reverse();
}
}
class CompressDecorator extends TextDecorator {
public CompressDecorator(TextProcessor processor) {
super(processor);
}
public String process(String text) {
String result = processor.process(text);
return "[压缩]" + result.replaceAll("\\s", "");
}
}
// 使用 - 灵活组合功能
TextProcessor processor = new PlainText();
System.out.println(processor.process("Hello World"));
// 加密装饰
processor = new EncryptDecorator(processor);
System.out.println(processor.process("Hello World"));
// 再加压缩装饰
processor = new CompressDecorator(processor);
System.out.println(processor.process("Hello World"));
核心价值:动态组合对象功能,避免类爆炸
8. 代理模式 (Proxy)
需求场景:开发一个图片查看器,需要显示大量高分辨率图片,要求:
- 提高加载性能,避免一次性加载所有图片
- 支持权限控制,只有VIP用户能查看高清图
- 添加缓存机制,避免重复加载
为什么用代理而不是直接调用?
- ❌ 直接调用:无法控制访问,无法添加额外功能
- ❌ 修改原类:违反开闭原则,增加类的复杂度
- ✅ 代理模式:在不修改原对象的情况下控制访问
interface ImageViewer {
void displayImage(String filename);
}
// 真实对象 - 实际的图片加载
class HighResolutionImage implements ImageViewer {
private String filename;
public HighResolutionImage(String filename) {
this.filename = filename;
loadImage(); // 耗时操作
}
private void loadImage() {
System.out.println("从磁盘加载高分辨率图片: " + filename);
}
public void displayImage(String filename) {
System.out.println("显示高分辨率图片: " + filename);
}
}
// 代理对象 - 控制访问
class ImageProxy implements ImageViewer {
private HighResolutionImage realImage;
private String filename;
private String userType;
private static Set<String> cache = new HashSet<>();
public ImageProxy(String filename, String userType) {
this.filename = filename;
this.userType = userType;
}
public void displayImage(String filename) {
// 权限检查
if (!"VIP".equals(userType)) {
System.out.println("显示低分辨率预览图: " + filename);
return;
}
// 缓存检查
if (cache.contains(filename)) {
System.out.println("从缓存显示: " + filename);
return;
}
// 延迟加载
if (realImage == null) {
realImage = new HighResolutionImage(filename);
}
realImage.displayImage(filename);
cache.add(filename);
}
}
// 使用 - 通过代理控制访问
ImageViewer vipImage = new ImageProxy("photo.jpg", "VIP");
ImageViewer normalImage = new ImageProxy("photo.jpg", "NORMAL");
vipImage.displayImage("photo.jpg"); // 加载高清图
normalImage.displayImage("photo.jpg"); // 显示预览图
vipImage.displayImage("photo.jpg"); // 从缓存显示
核心价值:在不修改对象的前提下控制访问
9. 外观模式 (Facade)
需求场景:开发一个智能家居控制系统,用户希望通过简单的语音命令控制多个设备,要求:
- 一个命令能控制多个相关设备
- 隐藏复杂的设备控制细节
- 提供简单易用的高层接口
为什么用外观而不是让客户端直接调用?
- ❌ 客户端直接调用:需要了解所有子系统的接口,代码复杂
- ❌ 把逻辑放在客户端:重复代码,难以维护
- ✅ 外观模式:提供统一的简化接口,隐藏复杂性
// 复杂的子系统
class Light {
public void turnOn() { System.out.println("灯光打开"); }
public void turnOff() { System.out.println("灯光关闭"); }
public void dim(int level) { System.out.println("灯光调至" + level + "%"); }
}
class AirConditioner {
public void turnOn() { System.out.println("空调启动"); }
public void setTemperature(int temp) { System.out.println("温度设为" + temp + "°C"); }
}
class Television {
public void turnOn() { System.out.println("电视打开"); }
public void setChannel(int channel) { System.out.println("切换到" + channel + "频道"); }
}
class SoundSystem {
public void turnOn() { System.out.println("音响开启"); }
public void setVolume(int volume) { System.out.println("音量设为" + volume); }
}
// 外观类 - 简化复杂操作
class SmartHomeFacade {
private Light light;
private AirConditioner ac;
private Television tv;
private SoundSystem sound;
public SmartHomeFacade() {
light = new Light();
ac = new AirConditioner();
tv = new Television();
sound = new SoundSystem();
}
// 一键回家模式
public void arriveHome() {
System.out.println("=== 回家模式启动 ===");
light.turnOn();
light.dim(70);
ac.turnOn();
ac.setTemperature(26);
System.out.println("=== 欢迎回家 ===");
}
// 一键观影模式
public void watchMovie() {
System.out.println("=== 观影模式启动 ===");
light.dim(20);
tv.turnOn();
tv.setChannel(5);
sound.turnOn();
sound.setVolume(30);
System.out.println("=== 享受观影时光 ===");
}
// 一键睡眠模式
public void sleep() {
System.out.println("=== 睡眠模式启动 ===");
light.turnOff();
tv.turnOff();
sound.turnOff();
ac.setTemperature(24);
System.out.println("=== 晚安 ===");
}
}
// 使用 - 简单的高层接口
SmartHomeFacade home = new SmartHomeFacade();
home.arriveHome(); // 一键操作多个设备
home.watchMovie(); // 一键切换场景
home.sleep(); // 一键关闭
核心价值:为复杂子系统提供简单统一的接口
10. 组合模式 (Composite)
需求场景:开发一个文件管理器,需要统一处理文件和文件夹的操作,要求:
- 文件夹可以包含文件和子文件夹
- 对文件夹的操作要递归应用到所有子项
- 客户端不需要区分处理文件还是文件夹
为什么用组合而不是分别处理?
- ❌ 分别处理:客户端需要判断类型,代码复杂
- ❌ 用继承:无法表达文件夹包含关系
- ✅ 组合模式:统一接口处理,支持递归结构
// 统一接口
abstract class FileSystemItem {
protected String name;
public FileSystemItem(String name) {
this.name = name;
}
public abstract void display(String indent);
public abstract long getSize();
}
// 叶子节点 - 文件
class File extends FileSystemItem {
private long size;
public File(String name, long size) {
super(name);
this.size = size;
}
public void display(String indent) {
System.out.println(indent + "📄 " + name + " (" + size + " bytes)");
}
public long getSize() {
return size;
}
}
// 组合节点 - 文件夹
class Folder extends FileSystemItem {
private List<FileSystemItem> children = new ArrayList<>();
public Folder(String name) {
super(name);
}
public void add(FileSystemItem item) {
children.add(item);
}
public void display(String indent) {
System.out.println(indent + "📁 " + name + "/");
for (FileSystemItem child : children) {
child.display(indent + " ");
}
}
public long getSize() {
long totalSize = 0;
for (FileSystemItem child : children) {
totalSize += child.getSize();
}
return totalSize;
}
}
// 使用 - 统一处理文件和文件夹
Folder root = new Folder("项目根目录");
root.add(new File("README.md", 1024));
root.add(new File("pom.xml", 2048));
Folder src = new Folder("src");
src.add(new File("Main.java", 5120));
src.add(new File("Utils.java", 3072));
root.add(src);
// 统一操作 - 不区分文件还是文件夹
root.display("");
System.out.println("总大小: " + root.getSize() + " bytes");
核心价值:统一处理单个对象和组合对象
11. 桥接模式 (Bridge)
需求场景:开发一个图形绘制程序,需要支持多种形状在不同平台上绘制,要求:
- 形状类型可以独立扩展(圆形、矩形、三角形等)
- 绘制平台可以独立扩展(Windows、Linux、Web等)
- 避免形状数量×平台数量的类爆炸问题
为什么用桥接而不是继承?
- ❌ 继承:N种形状×M个平台=N×M个类
- ❌ 接口继承:仍然存在组合爆炸
- ✅ 桥接模式:抽象和实现分离,各自独立扩展
// 实现接口 - 绘制平台
interface DrawingAPI {
void drawLine(int x1, int y1, int x2, int y2);
void drawCircle(int x, int y, int radius);
}
// 具体实现 - Windows平台
class WindowsDrawingAPI implements DrawingAPI {
public void drawLine(int x1, int y1, int x2, int y2) {
System.out.println("Windows绘制直线: (" + x1 + "," + y1 + ") to (" + x2 + "," + y2 + ")");
}
public void drawCircle(int x, int y, int radius) {
System.out.println("Windows绘制圆形: 中心(" + x + "," + y + ") 半径:" + radius);
}
}
// 具体实现 - Linux平台
class LinuxDrawingAPI implements DrawingAPI {
public void drawLine(int x1, int y1, int x2, int y2) {
System.out.println("Linux绘制直线: [" + x1 + "," + y1 + "]->[" + x2 + "," + y2 + "]");
}
public void drawCircle(int x, int y, int radius) {
System.out.println("Linux绘制圆形: center(" + x + "," + y + ") r=" + radius);
}
}
// 抽象 - 形状
abstract class Shape {
protected DrawingAPI drawingAPI;
protected Shape(DrawingAPI drawingAPI) {
this.drawingAPI = drawingAPI;
}
public abstract void draw();
}
// 扩展抽象 - 具体形状
class Circle extends Shape {
private int x, y, radius;
public Circle(int x, int y, int radius, DrawingAPI drawingAPI) {
super(drawingAPI);
this.x = x;
this.y = y;
this.radius = radius;
}
public void draw() {
drawingAPI.drawCircle(x, y, radius);
}
}
class Rectangle extends Shape {
private int x, y, width, height;
public Rectangle(int x, int y, int width, int height, DrawingAPI drawingAPI) {
super(drawingAPI);
this.x = x; this.y = y; this.width = width; this.height = height;
}
public void draw() {
drawingAPI.drawLine(x, y, x + width, y);
drawingAPI.drawLine(x + width, y, x + width, y + height);
drawingAPI.drawLine(x + width, y + height, x, y + height);
drawingAPI.drawLine(x, y + height, x, y);
}
}
// 使用 - 抽象和实现独立变化
Shape[] shapes = {
new Circle(10, 10, 5, new WindowsDrawingAPI()),
new Circle(20, 20, 8, new LinuxDrawingAPI()),
new Rectangle(0, 0, 10, 5, new WindowsDrawingAPI())
};
for (Shape shape : shapes) {
shape.draw();
}
核心价值:抽象与实现分离,避免类爆炸
12. 享元模式 (Flyweight)
需求场景:开发一个在线文档编辑器,需要处理大量文字字符,每个字符都有字体、大小、颜色等属性,要求:
- 支持百万级字符的文档
- 节约内存占用
- 保持良好的性能
为什么用享元而不是每个字符一个对象?
- ❌ 每字符一对象:百万字符=百万对象,内存爆炸
- ❌ 静态缓存:无法处理不同字体样式
- ✅ 享元模式:共享相同字符,只存储位置等外在状态
// 享元接口
interface CharacterFlyweight {
void display(int row, int col, String color);
}
// 具体享元 - 只存储内在状态(字符和字体)
class ConcreteCharacter implements CharacterFlyweight {
private final char character; // 内在状态,不变的
private final String font; // 内在状态,不变的
public ConcreteCharacter(char character, String font) {
this.character = character;
this.font = font;
}
// 外在状态(位置、颜色)作为参数传入
public void display(int row, int col, String color) {
System.out.println("显示字符 '" + character + "' " + font +
" 位置:(" + row + "," + col + ") 颜色:" + color);
}
}
// 享元工厂 - 管理和复用享元对象
class CharacterFactory {
private static Map<String, CharacterFlyweight> flyweights = new HashMap<>();
public static CharacterFlyweight getCharacter(char c, String font) {
String key = c + ":" + font;
CharacterFlyweight flyweight = flyweights.get(key);
if (flyweight == null) {
flyweight = new ConcreteCharacter(c, font);
flyweights.put(key, flyweight);
System.out.println("创建享元: " + key);
}
return flyweight;
}
public static int getCreatedCount() {
return flyweights.size();
}
}
// 文档类 - 存储外在状态
class Document {
private List<CharacterContext> characters = new ArrayList<>();
private static class CharacterContext {
CharacterFlyweight flyweight;
int row, col;
String color;
CharacterContext(CharacterFlyweight flyweight, int row, int col, String color) {
this.flyweight = flyweight;
this.row = row;
this.col = col;
this.color = color;
}
}
public void addCharacter(char c, String font, int row, int col, String color) {
CharacterFlyweight flyweight = CharacterFactory.getCharacter(c, font);
characters.add(new CharacterContext(flyweight, row, col, color));
}
public void display() {
for (CharacterContext context : characters) {
context.flyweight.display(context.row, context.col, context.color);
}
}
}
// 使用 - 大量字符共享少量对象
Document doc = new Document();
// 添加文本 "Hello World",相同字符共享享元
doc.addCharacter('H', "Arial", 0, 0, "black");
doc.addCharacter('e', "Arial", 0, 1, "black");
doc.addCharacter('l', "Arial", 0, 2, "black");
doc.addCharacter('l', "Arial", 0, 3, "black"); // 复用'l'
doc.addCharacter('o', "Arial", 0, 4, "black");
doc.addCharacter(' ', "Arial", 0, 5, "black");
doc.addCharacter('W', "Arial", 0, 6, "red");
doc.addCharacter('o', "Arial", 0, 7, "red"); // 复用'o'但颜色不同
doc.addCharacter('r', "Arial", 0, 8, "red");
doc.addCharacter('l', "Arial", 0, 9, "red"); // 复用'l'
doc.addCharacter('d', "Arial", 0, 10, "red");
doc.display();
System.out.println("创建的享元对象数量: " + CharacterFactory.getCreatedCount());
核心价值:通过共享减少大量相似对象的内存占用
三、行为型模式(11种)
13. 观察者模式 (Observer)
需求场景:开发一个股票监控系统,多个投资者需要实时关注股票价格变动,要求:
- 股票价格变动时自动通知所有关注者
- 投资者可以随时取消关注
- 新增投资者不影响现有系统
为什么用观察者而不是定时查询?
- ❌ 定时查询:延迟高,资源浪费
- ❌ 硬编码通知:添加新观察者需要修改代码
- ✅ 观察者模式:价格变动时主动通知,松耦合
// 观察者接口
interface StockObserver {
void update(String stockName, double price);
}
// 具体观察者 - 投资者
class Investor implements StockObserver {
private String name;
public Investor(String name) {
this.name = name;
}
public void update(String stockName, double price) {
System.out.println(name + " 收到通知: " + stockName + " 价格 ¥" + price);
// 根据价格做出投资决策
if (price > 100) {
System.out.println(name + " -> 价格过高,考虑卖出");
} else if (price < 80) {
System.out.println(name + " -> 价格较低,考虑买入");
}
}
}
// 被观察者 - 股票
class Stock {
private List<StockObserver> observers = new ArrayList<>();
private String name;
private double price;
public Stock(String name) {
this.name = name;
}
public void addObserver(StockObserver observer) {
observers.add(observer);
}
public void removeObserver(StockObserver observer) {
observers.remove(observer);
}
public void setPrice(double price) {
System.out.println("\n=== " + name + " 价格变动: ¥" + price + " ===");
this.price = price;
notifyObservers();
}
private void notifyObservers() {
for (StockObserver observer : observers) {
observer.update(name, price);
}
}
}
// 使用 - 一对多依赖关系
Stock appleStock = new Stock("苹果股票");
Investor zhang = new Investor("张三");
Investor li = new Investor("李四");
appleStock.addObserver(zhang);
appleStock.addObserver(li);
appleStock.setPrice(120.0); // 自动通知所有投资者
appleStock.setPrice(75.0); // 再次通知
核心价值:一对多依赖,状态变化时自动通知
14. 策略模式 (Strategy)
需求场景:电商系统需要支持多种促销策略(满减、打折、积分抵扣),要求:
- 根据用户类型和活动规则选择不同策略
- 新增促销策略不修改现有代码
- 策略可以在运行时动态切换
为什么用策略而不是if-else?
- ❌ if-else:新增策略需要修改现有代码,违反开闭原则
- ❌ 继承:客户端需要知道具体子类
- ✅ 策略模式:算法封装成独立类,可以互换
// 策略接口
interface PricingStrategy {
double calculatePrice(double originalPrice);
String getDescription();
}
// 具体策略
class RegularPricing implements PricingStrategy {
public double calculatePrice(double originalPrice) {
return originalPrice;
}
public String getDescription() {
return "正常价格";
}
}
class DiscountPricing implements PricingStrategy {
private double discount;
public DiscountPricing(double discount) {
this.discount = discount;
}
public double calculatePrice(double originalPrice) {
return originalPrice * (1 - discount);
}
public String getDescription() {
return (int)(discount * 100) + "% 折扣";
}
}
class VipPricing implements PricingStrategy {
public double calculatePrice(double originalPrice) {
// VIP享受8.5折,满100减10
double vipPrice = originalPrice * 0.85;
if (vipPrice >= 100) {
vipPrice -= 10;
}
return vipPrice;
}
public String getDescription() {
return "VIP价格(8.5折+满100减10)";
}
}
// 环境类 - 购物车
class ShoppingCart {
private PricingStrategy strategy;
private double originalPrice;
public ShoppingCart(double originalPrice) {
this.originalPrice = originalPrice;
this.strategy = new RegularPricing(); // 默认策略
}
public void setPricingStrategy(PricingStrategy strategy) {
this.strategy = strategy;
}
public void checkout() {
double finalPrice = strategy.calculatePrice(originalPrice);
System.out.println("原价: ¥" + originalPrice);
System.out.println("策略: " + strategy.getDescription());
System.out.println("实付: ¥" + finalPrice);
System.out.println("节省: ¥" + (originalPrice - finalPrice));
System.out.println("---");
}
}
// 使用 - 根据用户类型选择策略
ShoppingCart cart = new ShoppingCart(200.0);
// 普通用户
cart.checkout();
// 活动期间 - 7折优惠
cart.setPricingStrategy(new DiscountPricing(0.3));
cart.checkout();
// VIP用户
cart.setPricingStrategy(new VipPricing());
cart.checkout();
核心价值:将算法封装成可互换的策略类
15. 命令模式 (Command)
需求场景:开发一个智能家居遥控器,需要控制多种设备,要求:
- 支持撤销操作(如误按了关灯)
- 支持宏命令(一键执行多个操作)
- 可以记录操作历史
为什么用命令而不是直接调用?
- ❌ 直接调用:无法撤销,无法记录历史
- ❌ 保存参数:撤销逻辑复杂,难以管理
- ✅ 命令模式:将请求封装成对象,支持撤销和队列
// 命令接口
interface Command {
void execute();
void undo();
}
// 接收者 - 灯泡
class Light {
private boolean isOn = false;
public void turnOn() {
isOn = true;
System.out.println("灯已打开");
}
public void turnOff() {
isOn = false;
System.out.println("灯已关闭");
}
public boolean isOn() {
return isOn;
}
}
// 具体命令
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOn();
}
public void undo() {
light.turnOff();
}
}
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOff();
}
public void undo() {
light.turnOn();
}
}
// 宏命令 - 组合多个命令
class MacroCommand implements Command {
private Command[] commands;
public MacroCommand(Command[] commands) {
this.commands = commands;
}
public void execute() {
System.out.println("执行宏命令:");
for (Command command : commands) {
command.execute();
}
}
public void undo() {
System.out.println("撤销宏命令:");
// 逆序撤销
for (int i = commands.length - 1; i >= 0; i--) {
commands[i].undo();
}
}
}
// 调用者 - 遥控器
class RemoteControl {
private Command lastCommand;
public void setCommand(Command command) {
command.execute();
lastCommand = command;
}
public void pressUndo() {
if (lastCommand != null) {
System.out.println("撤销上一个操作:");
lastCommand.undo();
}
}
}
// 使用 - 支持撤销的遥控器
Light livingRoomLight = new Light();
Light bedRoomLight = new Light();
RemoteControl remote = new RemoteControl();
// 单个命令
remote.setCommand(new LightOnCommand(livingRoomLight));
remote.pressUndo(); // 撤销
// 宏命令 - 一键关闭所有灯
Command[] allOffCommands = {
new LightOffCommand(livingRoomLight),
new LightOffCommand(bedRoomLight)
};
MacroCommand allOff = new MacroCommand(allOffCommands);
remote.setCommand(allOff);
remote.pressUndo(); // 撤销宏命令
核心价值:将请求封装成对象,支持撤销和宏操作
16. 状态模式 (State)
需求场景:开发一个电梯控制系统,电梯有多种状态(停止、上行、下行、维护),不同状态下的操作行为不同,要求:
- 状态改变时行为自动改变
- 新增状态不影响现有代码
- 避免复杂的状态判断逻辑
为什么用状态而不是if-else?
- ❌ if-else:状态多了代码复杂,难以维护
- ❌ 枚举+switch:仍然是集中式判断,违反开闭原则
- ✅ 状态模式:每种状态独立处理,易于扩展
// 状态接口
interface ElevatorState {
void openDoor(ElevatorContext context);
void closeDoor(ElevatorContext context);
void moveUp(ElevatorContext context);
void moveDown(ElevatorContext context);
}
// 环境类 - 电梯
class ElevatorContext {
private ElevatorState state;
private int currentFloor = 1;
public ElevatorContext() {
state = new StoppedState(); // 初始状态
}
public void setState(ElevatorState state) {
System.out.println("电梯状态切换为: " + state.getClass().getSimpleName());
this.state = state;
}
public void openDoor() { state.openDoor(this); }
public void closeDoor() { state.closeDoor(this); }
public void moveUp() { state.moveUp(this); }
public void moveDown() { state.moveDown(this); }
public int getCurrentFloor() { return currentFloor; }
public void setCurrentFloor(int floor) { this.currentFloor = floor; }
}
// 具体状态 - 停止状态
class StoppedState implements ElevatorState {
public void openDoor(ElevatorContext context) {
System.out.println("电梯门打开");
}
public void closeDoor(ElevatorContext context) {
System.out.println("电梯门关闭");
}
public void moveUp(ElevatorContext context) {
System.out.println("电梯开始上行");
context.setState(new MovingUpState());
}
public void moveDown(ElevatorContext context) {
System.out.println("电梯开始下行");
context.setState(new MovingDownState());
}
}
// 具体状态 - 上行状态
class MovingUpState implements ElevatorState {
public void openDoor(ElevatorContext context) {
System.out.println("电梯运行中,无法开门");
}
public void closeDoor(ElevatorContext context) {
System.out.println("电梯门已关闭,正在上行");
}
public void moveUp(ElevatorContext context) {
System.out.println("电梯继续上行到" + (context.getCurrentFloor() + 1) + "楼");
context.setCurrentFloor(context.getCurrentFloor() + 1);
// 到达目标楼层,停止
System.out.println("到达目标楼层,电梯停止");
context.setState(new StoppedState());
}
public void moveDown(ElevatorContext context) {
System.out.println("电梯正在上行,先停止再下行");
context.setState(new StoppedState());
}
}
class MovingDownState implements ElevatorState {
public void openDoor(ElevatorContext context) {
System.out.println("电梯运行中,无法开门");
}
public void closeDoor(ElevatorContext context) {
System.out.println("电梯门已关闭,正在下行");
}
public void moveUp(ElevatorContext context) {
System.out.println("电梯正在下行,先停止再上行");
context.setState(new StoppedState());
}
public void moveDown(ElevatorContext context) {
System.out.println("电梯继续下行到" + (context.getCurrentFloor() - 1) + "楼");
context.setCurrentFloor(context.getCurrentFloor() - 1);
System.out.println("到达目标楼层,电梯停止");
context.setState(new StoppedState());
}
}
// 使用 - 状态决定行为
ElevatorContext elevator = new ElevatorContext();
elevator.openDoor(); // 停止状态可以开门
elevator.moveUp(); // 切换到上行状态
elevator.openDoor(); // 上行状态无法开门
elevator.moveUp(); // 继续上行并到达
elevator.openDoor(); // 停止状态又可以开门了
核心价值:状态改变时行为自动改变,避免复杂判断
17. 责任链模式 (Chain of Responsibility)
需求场景:开发一个客服系统,不同类型的问题需要不同级别的客服处理,要求:
- 按级别逐层处理问题
- 可以灵活调整处理链结构
- 发送者不需要知道具体哪个处理者会处理
为什么用责任链而不是直接分派?
- ❌ 直接分派:客户端需要知道所有处理者,耦合度高
- ❌ 集中判断:处理逻辑集中,难以扩展
- ✅ 责任链模式:松散耦合,处理者可以动态组合
// 问题类型
enum IssueType {
BASIC, TECHNICAL, BILLING, VIP
}
// 问题实体
class CustomerIssue {
private IssueType type;
private String description;
private String customerLevel;
public CustomerIssue(IssueType type, String description, String customerLevel) {
this.type = type;
this.description = description;
this.customerLevel = customerLevel;
}
public IssueType getType() { return type; }
public String getDescription() { return description; }
public String getCustomerLevel() { return customerLevel; }
}
// 抽象处理者
abstract class SupportHandler {
protected SupportHandler nextHandler;
protected String handlerName;
public SupportHandler(String name) {
this.handlerName = name;
}
public void setNext(SupportHandler handler) {
this.nextHandler = handler;
}
public void handleIssue(CustomerIssue issue) {
if (canHandle(issue)) {
System.out.println(handlerName + " 处理问题: " + issue.getDescription());
solve(issue);
} else if (nextHandler != null) {
System.out.println(handlerName + " 无法处理,转交给上级");
nextHandler.handleIssue(issue);
} else {
System.out.println("所有客服都无法处理此问题");
}
}
protected abstract boolean canHandle(CustomerIssue issue);
protected abstract void solve(CustomerIssue issue);
}
// 具体处理者
class BasicSupportHandler extends SupportHandler {
public BasicSupportHandler() {
super("初级客服");
}
protected boolean canHandle(CustomerIssue issue) {
return issue.getType() == IssueType.BASIC;
}
protected void solve(CustomerIssue issue) {
System.out.println("提供基础帮助和FAQ解答");
}
}
class TechnicalSupportHandler extends SupportHandler {
public TechnicalSupportHandler() {
super("技术客服");
}
protected boolean canHandle(CustomerIssue issue) {
return issue.getType() == IssueType.TECHNICAL;
}
protected void solve(CustomerIssue issue) {
System.out.println("提供技术支持和解决方案");
}
}
class ManagerHandler extends SupportHandler {
public ManagerHandler() {
super("客服经理");
}
protected boolean canHandle(CustomerIssue issue) {
return issue.getType() == IssueType.BILLING ||
issue.getType() == IssueType.VIP ||
"VIP".equals(issue.getCustomerLevel());
}
protected void solve(CustomerIssue issue) {
System.out.println("经理亲自处理重要问题");
}
}
// 使用 - 构建处理链
SupportHandler basicSupport = new BasicSupportHandler();
SupportHandler techSupport = new TechnicalSupportHandler();
SupportHandler manager = new ManagerHandler();
// 构建责任链
basicSupport.setNext(techSupport);
techSupport.setNext(manager);
// 处理不同问题
CustomerIssue[] issues = {
new CustomerIssue(IssueType.BASIC, "如何修改密码", "普通"),
new CustomerIssue(IssueType.TECHNICAL, "软件崩溃", "普通"),
new CustomerIssue(IssueType.BILLING, "账单错误", "普通"),
new CustomerIssue(IssueType.BASIC, "账户咨询", "VIP")
};
for (CustomerIssue issue : issues) {
System.out.println("\n=== 处理问题: " + issue.getDescription() + " ===");
basicSupport.handleIssue(issue);
}
核心价值:沿链传递请求,直到有对象处理它
18. 模板方法模式 (Template Method)
需求场景:开发一个数据处理框架,需要处理不同格式的数据文件(CSV、XML、JSON),处理流程固定但具体步骤不同,要求:
- 统一处理流程,确保步骤不会遗漏
- 各种格式的具体处理逻辑可以定制
- 公共逻辑可以复用
为什么用模板方法而不是让子类完全实现?
- ❌ 完全实现:容易遗漏步骤,公共逻辑重复
- ❌ 接口定义:无法强制执行处理流程
- ✅ 模板方法:在父类定义骨架,子类实现具体步骤
// 抽象模板类
abstract class DataProcessor {
// 模板方法 - 定义处理流程
public final void processData(String filename) {
System.out.println("=== 开始处理数据文件: " + filename + " ===");
validateFile(filename);
String data = readData(filename);
String processedData = parseData(data);
String result = transformData(processedData);
saveResult(result);
if (needsCleanup()) { // 钩子方法
cleanup();
}
System.out.println("=== 数据处理完成 ===\n");
}
// 具体方法 - 公共逻辑
private void validateFile(String filename) {
System.out.println("验证文件存在性和权限");
}
private void saveResult(String result) {
System.out.println("保存处理结果到数据库");
}
// 抽象方法 - 子类必须实现
protected abstract String readData(String filename);
protected abstract String parseData(String data);
protected abstract String transformData(String data);
// 钩子方法 - 子类可以选择重写
protected boolean needsCleanup() {
return true;
}
protected void cleanup() {
System.out.println("清理临时文件");
}
}
// 具体类 - CSV处理器
class CsvDataProcessor extends DataProcessor {
protected String readData(String filename) {
System.out.println("读取CSV文件内容");
return "csv_raw_data";
}
protected String parseData(String data) {
System.out.println("解析CSV格式,按逗号分割");
return "csv_parsed_data";
}
protected String transformData(String data) {
System.out.println("转换CSV数据为标准格式");
return "csv_transformed_data";
}
}
// 具体类 - JSON处理器
class JsonDataProcessor extends DataProcessor {
protected String readData(String filename) {
System.out.println("读取JSON文件内容");
return "json_raw_data";
}
protected String parseData(String data) {
System.out.println("解析JSON格式");
return "json_parsed_data";
}
protected String transformData(String data) {
System.out.println("转换JSON数据为标准格式");
return "json_transformed_data";
}
// 重写钩子方法
protected boolean needsCleanup() {
return false; // JSON处理不需要清理
}
}
// 使用 - 相同流程,不同实现
DataProcessor csvProcessor = new CsvDataProcessor();
DataProcessor jsonProcessor = new JsonDataProcessor();
csvProcessor.processData("data.csv");
jsonProcessor.processData("data.json");
核心价值:在父类定义算法骨架,子类实现具体步骤
19. 迭代器模式 (Iterator)
需求场景:开发一个播放列表系统,需要支持多种遍历方式(顺序播放、随机播放、循环播放),要求:
- 提供统一的遍历接口,不暴露内部存储结构
- 支持多种遍历算法
- 可以同时进行多个遍历操作
为什么用迭代器而不是直接访问?
- ❌ 直接访问:暴露内部结构,客户端依赖具体实现
- ❌ 返回数组/列表:无法支持不同遍历方式
- ✅ 迭代器模式:统一接口,支持多种遍历算法
// 迭代器接口
interface Iterator<T> {
boolean hasNext();
T next();
}
// 容器接口
interface PlayList<T> {
Iterator<T> getIterator();
Iterator<T> getRandomIterator();
Iterator<T> getLoopIterator();
}
// 具体容器 - 音乐播放列表
class MusicPlayList implements PlayList<String> {
private String[] songs;
private int count = 0;
public MusicPlayList(int capacity) {
songs = new String[capacity];
}
public void addSong(String song) {
if (count < songs.length) {
songs[count++] = song;
}
}
// 顺序迭代器
public Iterator<String> getIterator() {
return new SequentialIterator();
}
// 随机迭代器
public Iterator<String> getRandomIterator() {
return new RandomIterator();
}
// 循环迭代器
public Iterator<String> getLoopIterator() {
return new LoopIterator();
}
// 顺序迭代器实现
private class SequentialIterator implements Iterator<String> {
private int position = 0;
public boolean hasNext() {
return position < count;
}
public String next() {
return hasNext() ? songs[position++] : null;
}
}
// 随机迭代器实现
private class RandomIterator implements Iterator<String> {
private List<Integer> indices;
private int position = 0;
public RandomIterator() {
indices = new ArrayList<>();
for (int i = 0; i < count; i++) {
indices.add(i);
}
Collections.shuffle(indices);
}
public boolean hasNext() {
return position < indices.size();
}
public String next() {
return hasNext() ? songs[indices.get(position++)] : null;
}
}
// 循环迭代器实现
private class LoopIterator implements Iterator<String> {
private int position = 0;
private int playCount = 0;
private final int maxLoop = 3; // 最多循环3次
public boolean hasNext() {
return playCount < maxLoop;
}
public String next() {
if (!hasNext()) return null;
String song = songs[position];
position = (position + 1) % count;
if (position == 0) { // 一轮结束
playCount++;
System.out.println("--- 第" + playCount + "轮播放完成 ---");
}
return song;
}
}
}
// 使用 - 统一的遍历接口,不同的遍历行为
MusicPlayList playList = new MusicPlayList(5);
playList.addSong("夜曲");
playList.addSong("青花瓷");
playList.addSong("稻香");
System.out.println("=== 顺序播放 ===");
Iterator<String> sequential = playList.getIterator();
while (sequential.hasNext()) {
System.out.println("播放: " + sequential.next());
}
System.out.println("\n=== 随机播放 ===");
Iterator<String> random = playList.getRandomIterator();
while (random.hasNext()) {
System.out.println("播放: " + random.next());
}
System.out.println("\n=== 循环播放 ===");
Iterator<String> loop = playList.getLoopIterator();
int count = 0;
while (loop.hasNext() && count < 8) { // 只播放8首演示
System.out.println("播放: " + loop.next());
count++;
}
核心价值:统一的遍历接口,支持多种遍历算法
20. 中介者模式 (Mediator)
需求场景:开发一个在线聊天室系统,用户可以加入不同房间聊天,要求:
- 用户之间不直接通信,通过聊天室转发
- 支持私聊和群聊
- 可以方便地添加新功能(如禁言、踢出等)
为什么用中介者而不是用户直接通信?
- ❌ 直接通信:用户间相互引用,耦合度高,难以管理
- ❌ 全局管理类:职责不清,违反单一职责原则
- ✅ 中介者模式:集中管理交互,降低对象间耦合
// 中介者接口
interface ChatMediator {
void sendMessage(String message, User sender, User receiver);
void sendGroupMessage(String message, User sender);
void addUser(User user);
void removeUser(User user);
}
// 抽象用户
abstract class User {
protected ChatMediator mediator;
protected String name;
protected boolean isMuted = false;
public User(String name, ChatMediator mediator) {
this.name = name;
this.mediator = mediator;
}
public abstract void sendMessage(String message, User receiver);
public abstract void sendGroupMessage(String message);
public abstract void receiveMessage(String message, User sender);
public String getName() { return name; }
public boolean isMuted() { return isMuted; }
public void setMuted(boolean muted) { this.isMuted = muted; }
}
// 具体中介者 - 聊天室
class ChatRoom implements ChatMediator {
private List<User> users = new ArrayList<>();
private String roomName;
public ChatRoom(String roomName) {
this.roomName = roomName;
}
public void addUser(User user) {
users.add(user);
System.out.println(user.getName() + " 加入聊天室: " + roomName);
sendSystemMessage(user.getName() + " 进入了聊天室");
}
public void removeUser(User user) {
users.remove(user);
System.out.println(user.getName() + " 离开聊天室: " + roomName);
sendSystemMessage(user.getName() + " 离开了聊天室");
}
public void sendMessage(String message, User sender, User receiver) {
if (sender.isMuted()) {
System.out.println("[系统] " + sender.getName() + " 被禁言,无法发送消息");
return;
}
System.out.println("[私聊] " + sender.getName() + " -> " + receiver.getName());
receiver.receiveMessage(message, sender);
}
public void sendGroupMessage(String message, User sender) {
if (sender.isMuted()) {
System.out.println("[系统] " + sender.getName() + " 被禁言,无法发送消息");
return;
}
System.out.println("[群聊] " + sender.getName() + " 在 " + roomName + " 说:");
for (User user : users) {
if (user != sender) { // 不发送给自己
user.receiveMessage(message, sender);
}
}
}
// 系统消息
private void sendSystemMessage(String message) {
System.out.println("[系统消息] " + message);
}
// 管理员功能 - 禁言用户
public void muteUser(String userName) {
for (User user : users) {
if (user.getName().equals(userName)) {
user.setMuted(true);
sendSystemMessage(userName + " 被禁言");
break;
}
}
}
}
// 具体用户
class ChatUser extends User {
public ChatUser(String name, ChatMediator mediator) {
super(name, mediator);
}
public void sendMessage(String message, User receiver) {
mediator.sendMessage(message, this, receiver);
}
public void sendGroupMessage(String message) {
mediator.sendGroupMessage(message, this);
}
public void receiveMessage(String message, User sender) {
System.out.println(name + " 收到消息: " + message);
}
}
// 使用 - 通过中介者管理复杂交互
ChatRoom gameRoom = new ChatRoom("游戏讨论室");
User alice = new ChatUser("Alice", gameRoom);
User bob = new ChatUser("Bob", gameRoom);
User charlie = new ChatUser("Charlie", gameRoom);
gameRoom.addUser(alice);
gameRoom.addUser(bob);
gameRoom.addUser(charlie);
// 群聊
alice.sendGroupMessage("大家好!有人一起玩游戏吗?");
bob.sendGroupMessage("我可以!");
// 私聊
bob.sendMessage("我们组队吧", alice);
// 管理员功能
gameRoom.muteUser("Charlie");
charlie.sendGroupMessage("我也想参加"); // 被禁言,无法发送
gameRoom.removeUser(bob);
核心价值:集中管理对象间复杂交互,降低耦合度
21. 备忘录模式 (Memento)
需求场景:开发一个绘图软件,需要支持撤销和重做功能,要求:
- 可以撤销多步操作
- 支持重做被撤销的操作
- 不破坏绘图对象的封装性
- 内存占用要合理
为什么用备忘录而不是直接保存状态?
- ❌ 公开所有属性:破坏封装性,不安全
- ❌ 深拷贝整个对象:内存占用大,性能差
- ✅ 备忘录模式:只保存必要状态,保持封装性
// 备忘录 - 保存绘图状态
class DrawingMemento {
private final List<String> shapes;
private final String background;
private final String timestamp;
public DrawingMemento(List<String> shapes, String background) {
this.shapes = new ArrayList<>(shapes); // 深拷贝
this.background = background;
this.timestamp = new Date().toString();
}
// 包访问权限,只有DrawingBoard可以访问
List<String> getShapes() { return new ArrayList<>(shapes); }
String getBackground() { return background; }
String getTimestamp() { return timestamp; }
}
// 原发器 - 绘图板
class DrawingBoard {
private List<String> shapes = new ArrayList<>();
private String background = "白色";
// 绘制操作
public void addShape(String shape) {
shapes.add(shape);
System.out.println("添加图形: " + shape);
displayBoard();
}
public void setBackground(String background) {
this.background = background;
System.out.println("设置背景: " + background);
displayBoard();
}
public void clear() {
shapes.clear();
System.out.println("清空画板");
displayBoard();
}
// 创建备忘录
public DrawingMemento saveState() {
System.out.println("保存状态: " + shapes.size() + " 个图形");
return new DrawingMemento(shapes, background);
}
// 恢复状态
public void restoreState(DrawingMemento memento) {
this.shapes = memento.getShapes();
this.background = memento.getBackground();
System.out.println("恢复状态到: " + memento.getTimestamp());
displayBoard();
}
private void displayBoard() {
System.out.println("当前画板: 背景=" + background +
", 图形=" + shapes + "\n");
}
}
// 管理者 - 历史记录管理器
class HistoryManager {
private Stack<DrawingMemento> undoStack = new Stack<>();
private Stack<DrawingMemento> redoStack = new Stack<>();
private final int maxHistorySize = 10;
// 保存状态
public void saveState(DrawingBoard board) {
DrawingMemento memento = board.saveState();
// 保存到撤销栈
if (undoStack.size() >= maxHistorySize) {
undoStack.remove(0); // 移除最老的状态
}
undoStack.push(memento);
// 清空重做栈(新操作后不能重做之前的撤销)
redoStack.clear();
}
// 撤销
public void undo(DrawingBoard board) {
if (!undoStack.isEmpty()) {
// 先保存当前状态到重做栈
redoStack.push(board.saveState());
// 恢复到上一个状态
DrawingMemento memento = undoStack.pop();
board.restoreState(memento);
System.out.println("撤销操作完成");
} else {
System.out.println("没有可撤销的操作");
}
}
// 重做
public void redo(DrawingBoard board) {
if (!redoStack.isEmpty()) {
// 先保存当前状态到撤销栈
undoStack.push(board.saveState());
// 恢复到重做状态
DrawingMemento memento = redoStack.pop();
board.restoreState(memento);
System.out.println("重做操作完成");
} else {
System.out.println("没有可重做的操作");
}
}
public void showHistory() {
System.out.println("撤销栈大小: " + undoStack.size());
System.out.println("重做栈大小: " + redoStack.size());
}
}
// 使用 - 支持撤销重做的绘图软件
DrawingBoard board = new DrawingBoard();
HistoryManager history = new HistoryManager();
// 绘制操作序列
board.addShape("圆形");
history.saveState(board);
board.addShape("矩形");
history.saveState(board);
board.setBackground("蓝色");
history.saveState(board);
board.addShape("三角形");
history.saveState(board);
System.out.println("=== 开始撤销操作 ===");
history.undo(board); // 撤销三角形
history.undo(board); // 撤销背景色
history.undo(board); // 撤销矩形
System.out.println("=== 开始重做操作 ===");
history.redo(board); // 重做矩形
history.redo(board); // 重做背景色
history.showHistory();
核心价值:保存对象状态快照,支持撤销重做功能
22. 解释器模式 (Interpreter)
需求场景:开发一个配置文件解析器,需要解析类似"if price > 100 then discount = 0.1"的规则表达式,要求:
- 支持条件判断、赋值操作
- 语法可扩展,容易添加新的操作符
- 表达式可以嵌套组合
为什么用解释器而不是字符串解析?
- ❌ 硬编码解析:每种语法都要写解析代码,难以扩展
- ❌ 正则表达式:复杂语法难以处理,不支持嵌套
- ✅ 解释器模式:每种语法规则独立实现,易于扩展
// 上下文 - 存储变量值
class Context {
private Map<String, Double> variables = new HashMap<>();
public void setVariable(String name, double value) {
variables.put(name, value);
System.out.println("设置变量: " + name + " = " + value);
}
public double getVariable(String name) {
return variables.getOrDefault(name, 0.0);
}
public void showVariables() {
System.out.println("当前变量: " + variables);
}
}
// 抽象表达式
interface Expression {
double interpret(Context context);
}
// 终结符表达式 - 数字
class NumberExpression implements Expression {
private double number;
public NumberExpression(double number) {
this.number = number;
}
public double interpret(Context context) {
return number;
}
@Override
public String toString() {
return String.valueOf(number);
}
}
// 终结符表达式 - 变量
class VariableExpression implements Expression {
private String variableName;
public VariableExpression(String variableName) {
this.variableName = variableName;
}
public double interpret(Context context) {
return context.getVariable(variableName);
}
@Override
public String toString() {
return variableName;
}
}
// 非终结符表达式 - 加法
class AddExpression implements Expression {
private Expression left, right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
public double interpret(Context context) {
return left.interpret(context) + right.interpret(context);
}
@Override
public String toString() {
return "(" + left + " + " + right + ")";
}
}
// 非终结符表达式 - 比较(大于)
class GreaterThanExpression implements Expression {
private Expression left, right;
public GreaterThanExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
public double interpret(Context context) {
return left.interpret(context) > right.interpret(context) ? 1.0 : 0.0;
}
@Override
public String toString() {
return "(" + left + " > " + right + ")";
}
}
// 非终结符表达式 - 条件执行
class IfThenExpression implements Expression {
private Expression condition;
private Expression thenExpression;
public IfThenExpression(Expression condition, Expression thenExpression) {
this.condition = condition;
this.thenExpression = thenExpression;
}
public double interpret(Context context) {
if (condition.interpret(context) > 0) { // 大于0表示true
System.out.println("条件成立,执行then部分");
return thenExpression.interpret(context);
} else {
System.out.println("条件不成立,跳过then部分");
return 0;
}
}
@Override
public String toString() {
return "if " + condition + " then " + thenExpression;
}
}
// 赋值表达式
class AssignExpression implements Expression {
private String variableName;
private Expression valueExpression;
public AssignExpression(String variableName, Expression valueExpression) {
this.variableName = variableName;
this.valueExpression = valueExpression;
}
public double interpret(Context context) {
double value = valueExpression.interpret(context);
context.setVariable(variableName, value);
return value;
}
@Override
public String toString() {
return variableName + " = " + valueExpression;
}
}
// 简单的表达式构建器
class RuleBuilder {
public static Expression buildDiscountRule() {
// 构建规则: if price > 100 then discount = 0.1
Expression price = new VariableExpression("price");
Expression hundred = new NumberExpression(100);
Expression condition = new GreaterThanExpression(price, hundred);
Expression discountValue = new NumberExpression(0.1);
Expression assignment = new AssignExpression("discount", discountValue);
return new IfThenExpression(condition, assignment);
}
public static Expression buildVipRule() {
// 构建规则: if (price > 200 and vip = 1) then discount = 0.2
Expression price = new VariableExpression("price");
Expression twoHundred = new NumberExpression(200);
Expression priceCondition = new GreaterThanExpression(price, twoHundred);
Expression vip = new VariableExpression("vip");
Expression one = new NumberExpression(1);
Expression vipCondition = new GreaterThanExpression(vip, new NumberExpression(0.5)); // 简化and逻辑
Expression discountValue = new NumberExpression(0.2);
Expression assignment = new AssignExpression("discount", discountValue);
return new IfThenExpression(priceCondition, assignment);
}
}
// 使用 - 解释执行规则表达式
Context context = new Context();
// 测试普通用户规则
System.out.println("=== 测试普通用户折扣规则 ===");
context.setVariable("price", 150);
context.setVariable("discount", 0);
Expression discountRule = RuleBuilder.buildDiscountRule();
System.out.println("规则: " + discountRule);
discountRule.interpret(context);
context.showVariables();
// 测试VIP用户规则
System.out.println("\n=== 测试VIP用户折扣规则 ===");
context.setVariable("price", 250);
context.setVariable("vip", 1);
context.setVariable("discount", 0);
Expression vipRule = RuleBuilder.buildVipRule();
System.out.println("规则: " + vipRule);
vipRule.interpret(context);
context.showVariables();
// 测试条件不满足的情况
System.out.println("\n=== 测试条件不满足 ===");
context.setVariable("price", 50);
context.setVariable("discount", 0);
discountRule.interpret(context);
context.showVariables();
核心价值:为特定语言定义语法规则并解释执行
23. 访问者模式 (Visitor)
需求场景:开发一个电商系统的订单分析工具,需要对不同类型的商品进行多种分析(价格统计、重量计算、税费计算),要求:
- 在不修改商品类的情况下添加新的分析功能
- 支持对不同类型商品的专门处理
- 分析逻辑可以独立变化
为什么用访问者而不是在商品类中添加方法?
- ❌ 在商品类中添加:每次新增分析功能都要修改所有商品类
- ❌ 用instanceof判断:违反开闭原则,代码丑陋
- ✅ 访问者模式:分析逻辑与商品分离,易于扩展
// 访问者接口
interface ProductVisitor {
void visit(Book book);
void visit(Electronics electronics);
void visit(Clothing clothing);
}
// 商品接口
interface Product {
void accept(ProductVisitor visitor);
String getName();
double getPrice();
}
// 具体商品 - 书籍
class Book implements Product {
private String name;
private double price;
private int pages;
private String author;
public Book(String name, double price, int pages, String author) {
this.name = name;
this.price = price;
this.pages = pages;
this.author = author;
}
public void accept(ProductVisitor visitor) {
visitor.visit(this);
}
public String getName() { return name; }
public double getPrice() { return price; }
public int getPages() { return pages; }
public String getAuthor() { return author; }
}
// 具体商品 - 电子产品
class Electronics implements Product {
private String name;
private double price;
private double weight;
private int warrantyYears;
public Electronics(String name, double price, double weight, int warrantyYears) {
this.name = name;
this.price = price;
this.weight = weight;
this.warrantyYears = warrantyYears;
}
public void accept(ProductVisitor visitor) {
visitor.visit(this);
}
public String getName() { return name; }
public double getPrice() { return price; }
public double getWeight() { return weight; }
public int getWarrantyYears() { return warrantyYears; }
}
// 具体商品 - 服装
class Clothing implements Product {
private String name;
private double price;
private String size;
private String material;
public Clothing(String name, double price, String size, String material) {
this.name = name;
this.price = price;
this.size = size;
this.material = material;
}
public void accept(ProductVisitor visitor) {
visitor.visit(this);
}
public String getName() { return name; }
public double getPrice() { return price; }
public String getSize() { return size; }
public String getMaterial() { return material; }
}
// 具体访问者 - 价格统计
class PriceCalculatorVisitor implements ProductVisitor {
private double totalPrice = 0;
private int itemCount = 0;
public void visit(Book book) {
double bookPrice = book.getPrice();
// 书籍超过500页有折扣
if (book.getPages() > 500) {
bookPrice *= 0.9;
System.out.println("厚书折扣: " + book.getName() + " 优惠后价格: ¥" + bookPrice);
}
addToTotal(bookPrice);
}
public void visit(Electronics electronics) {
double electronicsPrice = electronics.getPrice();
// 电子产品有3年以上保修的加价
if (electronics.getWarrantyYears() > 3) {
electronicsPrice *= 1.1;
System.out.println("长保修加价: " + electronics.getName() + " 调整后价格: ¥" + electronicsPrice);
}
addToTotal(electronicsPrice);
}
public void visit(Clothing clothing) {
double clothingPrice = clothing.getPrice();
// 真丝材料的服装有额外税费
if ("真丝".equals(clothing.getMaterial())) {
clothingPrice *= 1.15;
System.out.println("真丝税费: " + clothing.getName() + " 含税价格: ¥" + clothingPrice);
}
addToTotal(clothingPrice);
}
private void addToTotal(double price) {
totalPrice += price;
itemCount++;
}
public void showResults() {
System.out.println("价格统计结果:");
System.out.println("总商品数: " + itemCount);
System.out.println("总价格: ¥" + String.format("%.2f", totalPrice));
System.out.println("平均价格: ¥" + String.format("%.2f", totalPrice / itemCount));
System.out.println();
}
}
// 具体访问者 - 重量计算
class WeightCalculatorVisitor implements ProductVisitor {
private double totalWeight = 0;
public void visit(Book book) {
// 书籍重量按页数估算
double bookWeight = book.getPages() * 0.005; // 每页5克
System.out.println("书籍重量: " + book.getName() + " 约" + bookWeight + "kg");
totalWeight += bookWeight;
}
public void visit(Electronics electronics) {
double weight = electronics.getWeight();
System.out.println("电子产品重量: " + electronics.getName() + " " + weight + "kg");
totalWeight += weight;
}
public void visit(Clothing clothing) {
// 服装重量按尺码估算
double clothingWeight;
switch (clothing.getSize().toUpperCase()) {
case "S": clothingWeight = 0.3; break;
case "M": clothingWeight = 0.4; break;
case "L": clothingWeight = 0.5; break;
case "XL": clothingWeight = 0.6; break;
default: clothingWeight = 0.4;
}
System.out.println("服装重量: " + clothing.getName() + " (" + clothing.getSize() + ") " + clothingWeight + "kg");
totalWeight += clothingWeight;
}
public void showResults() {
System.out.println("重量统计结果:");
System.out.println("总重量: " + String.format("%.2f", totalWeight) + "kg");
// 根据重量推荐物流方式
if (totalWeight < 2) {
System.out.println("推荐: 快递配送");
} else if (totalWeight < 10) {
System.out.println("推荐: 物流配送");
} else {
System.out.println("推荐: 货运配送");
}
System.out.println();
}
}
// 具体访问者 - 税费计算
class TaxCalculatorVisitor implements ProductVisitor {
private double totalTax = 0;
public void visit(Book book) {
// 书籍免税
System.out.println("书籍免税: " + book.getName() + " 税费: ¥0");
}
public void visit(Electronics electronics) {
// 电子产品13%增值税
double tax = electronics.getPrice() * 0.13;
System.out.println("电子产品税费: " + electronics.getName() + " 税费: ¥" + String.format("%.2f", tax));
totalTax += tax;
}
public void visit(Clothing clothing) {
// 服装17%增值税
double tax = clothing.getPrice() * 0.17;
System.out.println("服装税费: " + clothing.getName() + " 税费: ¥" + String.format("%.2f", tax));
totalTax += tax;
}
public void showResults() {
System.out.println("税费统计结果:");
System.out.println("总税费: ¥" + String.format("%.2f", totalTax));
System.out.println();
}
}
// 购物车 - 对象结构
class ShoppingCart {
private List<Product> products = new ArrayList<>();
public void addProduct(Product product) {
products.add(product);
System.out.println("添加商品: " + product.getName() + " ¥" + product.getPrice());
}
public void accept(ProductVisitor visitor) {
System.out.println("=== 开始" + visitor.getClass().getSimpleName() + "分析 ===");
for (Product product : products) {
product.accept(visitor);
}
}
public void showProducts() {
System.out.println("\n购物车商品清单:");
for (Product product : products) {
System.out.println("- " + product.getName() + " ¥" + product.getPrice());
}
System.out.println();
}
}
// 使用 - 不同分析访问同一批商品
ShoppingCart cart = new ShoppingCart();
// 添加不同类型的商品
cart.addProduct(new Book("设计模式", 89.0, 600, "GoF"));
cart.addProduct(new Book("Java编程", 59.0, 400, "张三"));
cart.addProduct(new Electronics("笔记本电脑", 5999.0, 2.1, 5));
cart.addProduct(new Electronics("手机", 3999.0, 0.2, 2));
cart.addProduct(new Clothing("真丝衬衫", 299.0, "M", "真丝"));
cart.addProduct(new Clothing("牛仔裤", 199.0, "L", "棉"));
cart.showProducts();
// 使用不同访问者进行分析
PriceCalculatorVisitor priceVisitor = new PriceCalculatorVisitor();
cart.accept(priceVisitor);
priceVisitor.showResults();
WeightCalculatorVisitor weightVisitor = new WeightCalculatorVisitor();
cart.accept(weightVisitor);
weightVisitor.showResults();
TaxCalculatorVisitor taxVisitor = new TaxCalculatorVisitor();
cart.accept(taxVisitor);
taxVisitor.showResults();
核心价值:在不修改元素类的前提下,定义作用于元素的新操作
总结:如何选择设计模式
🎯 问题导向的选择方法
当你遇到以下问题时:
- 需要全局唯一对象 → 单例模式
- 对象创建逻辑复杂 → 工厂/建造者模式
- 接口不兼容需要转换 → 适配器模式
- 需要动态添加功能 → 装饰器模式
- 需要控制对象访问 → 代理模式
- 子系统太复杂 → 外观模式
- 需要统一处理单个和组合对象 → 组合模式
- 一个对象变化需要通知多个对象 → 观察者模式
- 需要在运行时切换算法 → 策略模式
- 需要撤销操作 → 命令模式
- 对象行为随状态变化 → 状态模式
- 请求需要链式处理 → 责任链模式
- 流程固定但步骤可变 → 模板方法模式
- 需要统一遍历方式 → 迭代器模式
- 对象间交互复杂 → 中介者模式
- 需要保存对象状态 → 备忘录模式
- 需要解析特定语言 → 解释器模式
- 需要在不修改类的前提下添加操作 → 访问者模式
📊 使用频率与学习优先级
🥇 必须掌握(高频使用)
- 单例模式:配置管理、缓存、线程池
- 工厂模式:对象创建、框架设计
- 观察者模式:事件系统、MVC架构
- 策略模式:算法切换、业务规则
- 装饰器模式:功能扩展、中间件
🥈 重点理解(中频使用)
- 适配器模式:系统集成、遗留代码改造
- 代理模式:权限控制、缓存、懒加载
- 外观模式:API设计、子系统封装
- 命令模式:撤销重做、宏操作
- 模板方法模式:框架设计、流程控制
🥉 了解概念(低频使用)
- 抽象工厂、建造者、原型:特定场景使用
- 桥接、组合、享元:架构设计时考虑
- 状态、责任链:复杂业务逻辑
- 迭代器、中介者、备忘录:框架级开发
- 解释器、访问者:编译器、DSL设计
⚡ 快速决策树
遇到问题时的思考路径:
创建对象有问题?
├── 需要全局唯一 → 单例
├── 创建逻辑复杂 → 工厂方法
├── 需要一套产品 → 抽象工厂
├── 参数很多很复杂 → 建造者
└── 需要快速复制 → 原型
对象结构有问题?
├── 接口不匹配 → 适配器
├── 需要加功能 → 装饰器
├── 需要控制访问 → 代理
├── 系统太复杂 → 外观
├── 树形结构 → 组合
├── 抽象实现分离 → 桥接
└── 对象太多占内存 → 享元
对象交互有问题?
├── 一对多通知 → 观察者
├── 算法需要切换 → 策略
├── 需要撤销 → 命令
├── 状态影响行为 → 状态
├── 链式处理 → 责任链
├── 流程固定步骤可变 → 模板方法
├── 需要统一遍历 → 迭代器
├── 对象间交互复杂 → 中介者
├── 需要保存状态 → 备忘录
├── 需要解析语言 → 解释器
└── 需要新操作不改类 → 访问者
💡 设计模式使用原则
- 不要为了模式而模式 - 先有问题,再找模式
- 简单问题简单解决 - 复杂度要匹配问题复杂度
- 优先组合而不是继承 - 大多数模式都体现这个原则
- 面向接口编程 - 依赖抽象而不是具体实现
- 单一职责 - 一个类只做一件事
- 开闭原则 - 对扩展开放,对修改关闭
🚀 实际项目应用建议
小项目(个人项目、练手项目)
- 主要使用:单例、工厂、观察者、策略
- 重点练习模式的基本用法
中型项目(企业应用、团队开发)
- 增加使用:适配器、装饰器、代理、外观、命令
- 注重模式间的配合使用
大型项目(复杂系统、框架设计)
- 综合运用:所有模式都可能用到
- 注重架构层面的模式应用
**记住:设计模式是经验的总结,不是银弹。理解问题本质,选择合适方案,代码简洁可维护才是目标。
附录:23种设计模式使用频率排行
根据实际生产环境的使用情况,我将23种设计模式按使用频率从高到低进行排列:
🔥 极高频率使用(必须掌握)
1. 单例模式 (Singleton)
使用频率:⭐⭐⭐⭐⭐
- 数据库连接池管理
- 配置文件管理器(读取application.properties/yml)
- 日志记录器(Logger)
- Spring中的Bean默认作用域
- 缓存管理器(Redis连接管理)
- 线程池(ExecutorService)
2. 工厂模式 (Factory Method)
使用频率:⭐⭐⭐⭐⭐
- Spring的BeanFactory创建Bean
- 数据库连接工厂(不同数据库类型)
- 支付方式工厂(微信、支付宝、银联)
- 日志框架(SLF4J的LoggerFactory)
- 消息队列生产者创建(Kafka、RabbitMQ)
3. 代理模式 (Proxy)
使用频率:⭐⭐⭐⭐⭐
- Spring AOP实现(动态代理)
- MyBatis的Mapper接口代理
- RPC远程调用(Dubbo、Feign)
- 权限控制和安全检查
- 事务管理
- 缓存代理(二级缓存)
4. 策略模式 (Strategy)
使用频率:⭐⭐⭐⭐⭐
- 支付策略(不同支付方式的处理)
- 促销活动计算(满减、折扣、买赠)
- 文件上传策略(本地、OSS、S3)
- 登录方式策略(账号密码、手机验证码、第三方登录)
- 排序算法选择
- 数据导出格式(Excel、PDF、CSV)
5. 观察者模式 (Observer)
使用频率:⭐⭐⭐⭐⭐
- Spring的事件监听机制(ApplicationEvent)
- MQ消息订阅(订单创建后触发多个操作)
- 前端响应式框架(Vue、React的数据绑定)
- 系统监控告警
- 用户行为埋点
- 库存变动通知
🔥 高频率使用(重点掌握)
6. 装饰器模式 (Decorator)
使用频率:⭐⭐⭐⭐
- Java I/O流(BufferedReader装饰FileReader)
- Spring中的BeanWrapper
- 数据加密装饰
- 日志增强(添加追踪ID)
- HTTP请求/响应包装
- 缓存装饰
7. 模板方法模式 (Template Method)
使用频率:⭐⭐⭐⭐
- Spring的JdbcTemplate、RestTemplate
- Servlet的service方法
- 抽象类定义算法骨架(数据导入流程)
- 单元测试框架(JUnit的setUp/tearDown)
- 爬虫框架(通用爬取流程)
- 报表生成流程
8. 适配器模式 (Adapter)
使用频率:⭐⭐⭐⭐
- Spring MVC的HandlerAdapter
- 第三方接口适配(统一不同供应商接口)
- 老系统与新系统对接
- 日志框架适配(SLF4J适配Log4j)
- 数据库驱动适配
- 消息格式转换
9. 责任链模式 (Chain of Responsibility)
使用频率:⭐⭐⭐⭐
- Servlet的Filter链
- Spring Security的过滤器链
- 请求参数校验(多级校验)
- 审批流程(多级审批)
- 异常处理链
- 网关鉴权链路
10. 建造者模式 (Builder)
使用频率:⭐⭐⭐⭐
- Lombok的@Builder注解
- StringBuilder/StringBuffer
- HTTP客户端构建(OkHttpClient)
- 复杂对象创建(订单对象)
- SQL构建器(MyBatis的SQL Builder)
- 邮件对象构建
🔶 中等频率使用
11. 抽象工厂模式 (Abstract Factory)
使用频率:⭐⭐⭐
- 数据库访问层工厂(DAO工厂族)
- UI主题工厂(不同皮肤)
- 跨平台组件工厂
- 多数据源配置
12. 外观模式 (Facade)
使用频率:⭐⭐⭐
- 微服务聚合API(BFF层)
- 第三方SDK封装
- 复杂子系统的统一接口
- Service层聚合多个Manager
13. 组合模式 (Composite)
使用频率:⭐⭐⭐
- 树形菜单结构
- 组织架构树
- 文件目录结构
- 权限树管理
- 商品类目树
14. 迭代器模式 (Iterator)
使用频率:⭐⭐⭐
- Java集合框架(Iterator接口)
- 数据库结果集遍历(ResultSet)
- 分页查询迭代
- 自定义集合遍历
15. 命令模式 (Command)
使用频率:⭐⭐⭐
- 撤销/重做功能
- 任务队列调度
- 线程池任务提交(Runnable)
- 数据库事务回滚
- GUI按钮操作
16. 状态模式 (State)
使用频率:⭐⭐⭐
- 订单状态流转
- 工作流引擎
- TCP连接状态
- 游戏角色状态
- 审批流状态
🔷 低频率使用
17. 原型模式 (Prototype)
使用频率:⭐⭐
- 对象深拷贝(BeanUtils.copyProperties)
- Spring的prototype作用域
- 大对象复制优化
- 缓存对象克隆
18. 桥接模式 (Bridge)
使用频率:⭐⭐
- JDBC驱动(DriverManager)
- 消息发送桥接(短信、邮件)
- 跨平台图形库
- 多维度变化场景
19. 享元模式 (Flyweight)
使用频率:⭐⭐
- String常量池
- Integer缓存池(-128~127)
- 线程池
- 数据库连接池
- 对象池技术
20. 中介者模式 (Mediator)
使用频率:⭐⭐
- MVC中的Controller
- 聊天室服务器
- 航空管制系统
- 智能家居中控
21. 备忘录模式 (Memento)
使用频率:⭐
- 编辑器撤销功能
- 游戏存档
- 数据库事务快照
- 表单草稿保存
22. 访问者模式 (Visitor)
使用频率:⭐
- 编译器AST遍历
- 报表数据处理
- 对象结构稳定但操作多变
- XML文档解析
23. 解释器模式 (Interpreter)
使用频率:⭐
- 正则表达式引擎
- SQL解析器
- 表达式计算器(SpEL)
- 规则引擎
- 自定义DSL
💡 总结建议
优先掌握前10个模式,它们覆盖了90%以上的实际开发场景。特别是:
- 单例、工厂、代理、策略、观察者是最核心的5个模式
- Spring框架大量使用了这些设计模式,理解它们有助于深入学习框架源码
- 实际开发中往往组合使用多种设计模式,而不是单独使用
- 不要为了用设计模式而用,要根据实际场景选择合适的模式