《设计模式》第十篇:三大类型之行为型模式

本期内容为自己总结归档,共分十一章,本人遇到过的面试问题会重点标记。

《设计模式》第一篇:初识

《设计模式》第二篇:单例模式

《设计模式》第三篇:工厂模式

《设计模式》第四篇:观察模式

《设计模式》第五篇:策略模式

《设计模式》第六篇:装饰器模式

《设计模式》第七篇:适配器模式

《设计模式》第八篇:创建型模式

《设计模式》第九篇:结构型模式

《设计模式》第十篇:行为型模式

《设计模式》第十一篇:总结&常用案例

(若有任何疑问,可在评论区告诉我,看到就回复)

一、行为型模式全景

1.1 什么是行为型模式?

行为型模式关注对象之间的职责分配和通信方式,描述对象之间如何协作以及如何分配职责。它们定义了对象交互的模式,使系统能够更容易地应对变化。

行为型模式的核心关注点:

  1. 对象间通信:对象如何发送和接收消息

  2. 职责分配:哪个对象负责执行什么任务

  3. 算法封装:如何封装变化的行为

  4. 状态管理:对象状态如何影响行为

1.2 行为型模式的分类

GoF定义了11种行为型模式,它们可以分为三组:

1.3 行为型模式的核心思想

所有行为型模式都围绕一个核心理念:封装变化。将系统中经常变化的部分封装起来,让稳定的部分保持稳定。

二、责任链模式

2.1 责任链模式的定义

责任链模式使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

2.2 责任链模式的核心结构

2.3 责任链模式实现:审批流程

java 复制代码
// 处理者接口
public interface Approver {
    void setNextApprover(Approver next);
    void processRequest(PurchaseRequest request);
}

// 具体处理者:经理
public class Manager implements Approver {
    private Approver next;
    private static final double MAX_AMOUNT = 10000;
    
    @Override
    public void setNextApprover(Approver next) {
        this.next = next;
    }
    
    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() <= MAX_AMOUNT) {
            System.out.println("经理审批通过:¥" + request.getAmount());
        } else if (next != null) {
            System.out.println("经理无权审批,转交上级");
            next.processRequest(request);
        } else {
            System.out.println("无法处理该请求");
        }
    }
}

// 具体处理者:总监
public class Director implements Approver {
    private Approver next;
    private static final double MAX_AMOUNT = 50000;
    
    @Override
    public void setNextApprover(Approver next) {
        this.next = next;
    }
    
    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() <= MAX_AMOUNT) {
            System.out.println("总监审批通过:¥" + request.getAmount());
        } else if (next != null) {
            System.out.println("总监无权审批,转交上级");
            next.processRequest(request);
        } else {
            System.out.println("无法处理该请求");
        }
    }
}

// 具体处理者:CEO
public class CEO implements Approver {
    @Override
    public void setNextApprover(Approver next) {
        // CEO是最终处理者
    }
    
    @Override
    public void processRequest(PurchaseRequest request) {
        System.out.println("CEO审批通过:¥" + request.getAmount());
    }
}

// 客户端使用
public class ChainOfResponsibilityDemo {
    public static void main(String[] args) {
        System.out.println("=== 责任链模式:审批流程 ===");
        
        // 创建处理链
        Approver manager = new Manager();
        Approver director = new Director();
        Approver ceo = new CEO();
        
        manager.setNextApprover(director);
        director.setNextApprover(ceo);
        
        // 处理不同金额的请求
        PurchaseRequest request1 = new PurchaseRequest(5000);
        PurchaseRequest request2 = new PurchaseRequest(25000);
        PurchaseRequest request3 = new PurchaseRequest(100000);
        
        System.out.println("\n请求1: ¥5000");
        manager.processRequest(request1);
        
        System.out.println("\n请求2: ¥25000");
        manager.processRequest(request2);
        
        System.out.println("\n请求3: ¥100000");
        manager.processRequest(request3);
    }
}

2.4 责任链模式的特点

优点

  1. 降低耦合:发送者不需要知道具体处理者

  2. 灵活性:可以动态改变链中的处理者顺序

  3. 单一职责:每个处理者只处理自己能处理的请求

缺点

  1. 请求可能未被处理:如果链中没有合适的处理者

  2. 性能问题:长链可能导致性能下降

  3. 调试困难:请求处理路径可能不明确

适用场景

多级审批流程、过滤器链(如Servlet Filter)、事件传播机制、异常处理机

三、访问者模式

3.1 访问者模式的定义

访问者模式表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

3.2 访问者模式的核心结构

3.3 访问者模式实现:文档处理

java 复制代码
// 访问者接口
public interface DocumentVisitor {
    void visit(TextElement element);
    void visit(ImageElement element);
    void visit(TableElement element);
}

// 元素接口
public interface DocumentElement {
    void accept(DocumentVisitor visitor);
}

// 具体元素:文本元素
public class TextElement implements DocumentElement {
    private String content;
    
    public TextElement(String content) {
        this.content = content;
    }
    
    @Override
    public void accept(DocumentVisitor visitor) {
        visitor.visit(this);
    }
    
    public String getContent() {
        return content;
    }
    
    public int getWordCount() {
        return content.split("\\s+").length;
    }
}

// 具体元素:图片元素
public class ImageElement implements DocumentElement {
    private String filename;
    private int width;
    private int height;
    
    public ImageElement(String filename, int width, int height) {
        this.filename = filename;
        this.width = width;
        this.height = height;
    }
    
    @Override
    public void accept(DocumentVisitor visitor) {
        visitor.visit(this);
    }
    
    public String getFilename() {
        return filename;
    }
    
    public int getSizeInKB() {
        return (width * height) / 1000; // 简化计算
    }
}

// 具体元素:表格元素
public class TableElement implements DocumentElement {
    private int rows;
    private int columns;
    private String title;
    
    public TableElement(String title, int rows, int columns) {
        this.title = title;
        this.rows = rows;
        this.columns = columns;
    }
    
    @Override
    public void accept(DocumentVisitor visitor) {
        visitor.visit(this);
    }
    
    public int getCellCount() {
        return rows * columns;
    }
    
    public String getTitle() {
        return title;
    }
}

// 具体访问者:统计访问者
public class StatisticsVisitor implements DocumentVisitor {
    private int textCount = 0;
    private int imageCount = 0;
    private int tableCount = 0;
    private int totalWords = 0;
    private int totalImageSize = 0;
    
    @Override
    public void visit(TextElement element) {
        textCount++;
        totalWords += element.getWordCount();
        System.out.println("统计文本: " + element.getContent());
    }
    
    @Override
    public void visit(ImageElement element) {
        imageCount++;
        totalImageSize += element.getSizeInKB();
        System.out.println("统计图片: " + element.getFilename());
    }
    
    @Override
    public void visit(TableElement element) {
        tableCount++;
        System.out.println("统计表格: " + element.getTitle());
    }
    
    public void printReport() {
        System.out.println("\n=== 文档统计报告 ===");
        System.out.println("文本元素数量: " + textCount);
        System.out.println("图片元素数量: " + imageCount);
        System.out.println("表格元素数量: " + tableCount);
        System.out.println("总字数: " + totalWords);
        System.out.println("总图片大小: " + totalImageSize + " KB");
    }
}

// 具体访问者:导出访问者
public class ExportVisitor implements DocumentVisitor {
    private StringBuilder output = new StringBuilder();
    
    @Override
    public void visit(TextElement element) {
        output.append("[TEXT] ").append(element.getContent()).append("\n");
    }
    
    @Override
    public void visit(ImageElement element) {
        output.append("[IMAGE] ").append(element.getFilename())
              .append(" (").append(element.getSizeInKB()).append(" KB)\n");
    }
    
    @Override
    public void visit(TableElement element) {
        output.append("[TABLE] ").append(element.getTitle())
              .append(" (").append(element.getCellCount()).append(" cells)\n");
    }
    
    public String getOutput() {
        return output.toString();
    }
}

// 文档结构
public class Document {
    private List<DocumentElement> elements = new ArrayList<>();
    
    public void addElement(DocumentElement element) {
        elements.add(element);
    }
    
    public void accept(DocumentVisitor visitor) {
        for (DocumentElement element : elements) {
            element.accept(visitor);
        }
    }
}

// 客户端使用
public class VisitorPatternDemo {
    public static void main(String[] args) {
        System.out.println("=== 访问者模式:文档处理 ===");
        
        // 创建文档
        Document document = new Document();
        document.addElement(new TextElement("欢迎使用访问者模式"));
        document.addElement(new TextElement("这是一个示例文档"));
        document.addElement(new ImageElement("photo.jpg", 1920, 1080));
        document.addElement(new TableElement("销售数据", 5, 3));
        document.addElement(new ImageElement("chart.png", 800, 600));
        
        // 使用统计访问者
        System.out.println("\n1. 执行统计访问者:");
        StatisticsVisitor statsVisitor = new StatisticsVisitor();
        document.accept(statsVisitor);
        statsVisitor.printReport();
        
        // 使用导出访问者
        System.out.println("\n2. 执行导出访问者:");
        ExportVisitor exportVisitor = new ExportVisitor();
        document.accept(exportVisitor);
        System.out.println(exportVisitor.getOutput());
    }
}

3.4 访问者模式的特点

优点

  1. 开闭原则:容易添加新操作

  2. 单一职责:访问者专注于特定操作

  3. 算法集中:相关操作集中在一个访问者中

  4. 数据结构稳定:元素类结构不需要修改

缺点

  1. 违反封装:需要暴露元素内部细节

  2. 元素类修改困难:添加新元素类型需要修改所有访问者

  3. 依赖具体类:访问者依赖具体元素类

适用场景

数据结构稳定但操作频繁变化、需要对复杂对象结构执行多种不同操作、需要将相关操作集中在一起、编译器解释器等复杂结构处

总结

模式对比表

模式 主要目的 关键思想 适用场景
责任链 请求处理链 多个对象处理请求 审批流程、过滤器
命令 请求封装 将请求封装为对象 撤销/重做、队列
状态 状态驱动行为 状态改变行为改变 状态机、订单状态
策略 算法封装 封装可互换的算法 支付策略、排序算法
观察者 事件通知 一对多依赖通知 事件处理、数据同步
模板方法 算法骨架 定义算法骨架 框架设计、工作流
访问者 元素操作 不改变元素的操作 编译器、文档处理

核心价值回顾

行为型设计模式的核心价值在于优雅地管理对象间的交互和职责分配,让软件系统更加灵活、可维护和可扩展。

相关推荐
葫芦和十三17 小时前
图解 MongoDB 22|读写关注:持久性与一致性的档位选择
后端·mongodb·agent
葫芦和十三1 天前
图解 MongoDB 21|选举与 failover:Primary 是怎么选出来的
后端·mongodb·agent
GetcharZp1 天前
26k Star 开源内网穿透神器 NetBird,一分钟实现全球设备互联!
后端
考虑考虑1 天前
Mybatis实现批量插入
java·后端·mybatis
咖啡八杯1 天前
GoF设计模式——中介者模式
java·后端·spring·设计模式
lizhongxuan1 天前
多Agent之间的区别
后端
青石路1 天前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
杨充1 天前
1.面向对象设计思想
后端
IT_陈寒1 天前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
systemPro1 天前
2.6亿条设备数据,历史查询从超时到50ms,我做了什么
后端