news 2026/4/9 4:10:38

设计模式深度解析:策略模式、责任链模式与模板模式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
设计模式深度解析:策略模式、责任链模式与模板模式

临时插入一个额外知识换换思路,认识一下几个业务中常用的设计模式,尽可能讲明白、多多点赞支持~

引言

在软件开发过程中,设计模式是解决常见问题的经典方案。今天我们将深入探讨三种常用的行为型设计模式:策略模式、责任链模式和模板模式。每种模式都有其独特的适用场景和优势,能够帮助我们编写出更加灵活、可维护的代码。

1. 策略模式 (Strategy Pattern)

模式介绍

策略模式定义了一系列算法,将每个算法封装起来,并且使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。

核心思想

封装变化:将经常变化的算法部分抽象出来

面向接口:针对接口编程,而不是针对实现

组合优于继承:通过组合方式使用算法,避免继承带来的复杂性

适用场景

一个系统需要在多种算法中选择一种

有多个条件语句定义不同行为的情况

希望算法可以自由切换

需要隔离算法的使用和实现

经典示例:支付系统

/**

* 支付策略接口

* 定义所有支付方式必须实现的方法

*/

interface PaymentStrategy {

/**

* 执行支付

* @param amount 支付金额

* @return 支付结果

*/

boolean pay(double amount);

/**

* 获取支付方式名称

* @return 支付方式名称

*/

String getPaymentMethod();

}

/**

* 支付宝支付策略

* 实现支付宝特有的支付逻辑

*/

class AlipayStrategy implements PaymentStrategy {

@Override

public boolean pay(double amount) {

System.out.println("使用支付宝支付 " + amount + " 元");

// 调用支付宝SDK进行支付

System.out.println("调用支付宝接口...");

System.out.println("用户确认支付...");

System.out.println("支付成功!");

return true;

}

@Override

public String getPaymentMethod() {

return "支付宝";

}

}

/**

* 微信支付策略

* 实现微信支付特有的支付逻辑

*/

class WechatPayStrategy implements PaymentStrategy {

@Override

public boolean pay(double amount) {

System.out.println("使用微信支付 " + amount + " 元");

// 调用微信支付SDK进行支付

System.out.println("调用微信支付接口...");

System.out.println("用户输入密码...");

System.out.println("支付成功!");

return true;

}

@Override

public String getPaymentMethod() {

return "微信支付";

}

}

/**

* 银行卡支付策略

* 实现银行卡支付特有的支付逻辑

*/

class BankCardStrategy implements PaymentStrategy {

private String cardNumber;

private String cvv;

public BankCardStrategy(String cardNumber, String cvv) {

this.cardNumber = cardNumber;

this.cvv = cvv;

}

@Override

public boolean pay(double amount) {

System.out.println("使用银行卡支付 " + amount + " 元");

// 调用银行支付网关

System.out.println("验证银行卡信息...");

System.out.println("卡号: " + maskCardNumber(cardNumber));

System.out.println("调用银行支付网关...");

System.out.println("支付成功!");

return true;

}

@Override

public String getPaymentMethod() {

return "银行卡";

}

private String maskCardNumber(String cardNumber) {

// 隐藏银行卡号中间部分

if (cardNumber.length() > 8) {

return cardNumber.substring(0, 4) + " **** **** " + cardNumber.substring(cardNumber.length() - 4);

}

return cardNumber;

}

}

/**

* 支付上下文

* 负责管理和使用具体的支付策略

*/

class PaymentContext {

private PaymentStrategy paymentStrategy;

/**

* 设置支付策略

* @param paymentStrategy 具体的支付策略

*/

public void setPaymentStrategy(PaymentStrategy paymentStrategy) {

this.paymentStrategy = paymentStrategy;

}

/**

* 执行支付操作

* @param amount 支付金额

* @return 支付结果

*/

public boolean executePayment(double amount) {

if (paymentStrategy == null) {

throw new IllegalStateException("支付策略未设置");

}

System.out.println("开始" + paymentStrategy.getPaymentMethod() + "支付流程...");

return paymentStrategy.pay(amount);

}

}

/**

* 策略模式演示类

*/

public class StrategyPatternDemo {

public static void main(String[] args) {

// 创建支付上下文

PaymentContext context = new PaymentContext();

// 使用支付宝支付

System.out.println("=== 支付宝支付 ===");

context.setPaymentStrategy(new AlipayStrategy());

context.executePayment(100.0);

// 使用微信支付

System.out.println("\n=== 微信支付 ===");

context.setPaymentStrategy(new WechatPayStrategy());

context.executePayment(200.0);

// 使用银行卡支付

System.out.println("\n=== 银行卡支付 ===");

context.setPaymentStrategy(new BankCardStrategy("6225880112345678", "123"));

context.executePayment(300.0);

}

}

策略模式优势

开闭原则:新增支付方式无需修改现有代码

消除条件判断:避免大量的if-else语句

代码复用:相同算法可以在不同环境中复用

易于测试:每个策略都可以独立测试

2. 责任链模式 (Chain of Responsibility Pattern)

模式介绍

责任链模式将请求的发送者和接收者解耦,让多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

核心思想

解耦发送者和接收者:发送者不需要知道哪个对象会处理请求

动态组合:可以动态地添加或修改处理链

灵活处理:每个处理器可以选择处理请求或传递给下一个

适用场景

有多个对象可以处理同一个请求

想在不明确指定接收者的情况下向多个对象中的一个提交请求

需要动态指定一组对象处理请求

经典示例:请假审批系统

/**

* 请假请求类

* 包含请假的基本信息

*/

class LeaveRequest {

private String employeeName;

private int leaveDays;

private String reason;

public LeaveRequest(String employeeName, int leaveDays, String reason) {

this.employeeName = employeeName;

this.leaveDays = leaveDays;

this.reason = reason;

}

// Getter 方法

public String getEmployeeName() { return employeeName; }

public int getLeaveDays() { return leaveDays; }

public String getReason() { return reason; }

}

/**

* 审批处理器接口

* 定义审批处理器的基本行为

*/

interface ApprovalHandler {

/**

* 设置下一个处理器

* @param nextHandler 下一个审批处理器

*/

void setNextHandler(ApprovalHandler nextHandler);

/**

* 处理请假请求

* @param request 请假请求

* @return 处理结果

*/

boolean handleRequest(LeaveRequest request);

}

/**

* 组长审批处理器

* 处理1天以内的请假

*/

class GroupLeaderHandler implements ApprovalHandler {

private ApprovalHandler nextHandler;

@Override

public void setNextHandler(ApprovalHandler nextHandler) {

this.nextHandler = nextHandler;

}

@Override

public boolean handleRequest(LeaveRequest request) {

System.out.println("组长正在审批 " + request.getEmployeeName() + " 的请假申请...");

if (request.getLeaveDays() <= 1) {

System.out.println("✅ 组长批准 " + request.getEmployeeName() + " 请假 " +

request.getLeaveDays() + " 天,原因:" + request.getReason());

return true;

}

System.out.println("⏭️ 组长无权限审批 " + request.getLeaveDays() + " 天请假,转交上级");

return nextHandler != null && nextHandler.handleRequest(request);

}

}

/**

* 班长审批处理器

* 处理3天以内的请假

*/

class SquadLeaderHandler implements ApprovalHandler {

private ApprovalHandler nextHandler;

@Override

public void setNextHandler(ApprovalHandler nextHandler) {

this.nextHandler = nextHandler;

}

@Override

public boolean handleRequest(LeaveRequest request) {

System.out.println("班长正在审批 " + request.getEmployeeName() + " 的请假申请...");

if (request.getLeaveDays() <= 3) {

System.out.println("✅ 班长批准 " + request.getEmployeeName() + " 请假 " +

request.getLeaveDays() + " 天,原因:" + request.getReason());

return true;

}

System.out.println("⏭️ 班长无权限审批 " + request.getLeaveDays() + " 天请假,转交上级");

return nextHandler != null && nextHandler.handleRequest(request);

}

}

/**

* 副厂长审批处理器

* 处理3天以内的请假(与班长权限相同,但角色不同)

*/

class ViceManagerHandler implements ApprovalHandler {

private ApprovalHandler nextHandler;

@Override

public void setNextHandler(ApprovalHandler nextHandler) {

this.nextHandler = nextHandler;

}

@Override

public boolean handleRequest(LeaveRequest request) {

System.out.println("副厂长正在审批 " + request.getEmployeeName() + " 的请假申请...");

if (request.getLeaveDays() <= 3) {

System.out.println("✅ 副厂长批准 " + request.getEmployeeName() + " 请假 " +

request.getLeaveDays() + " 天,原因:" + request.getReason());

return true;

}

System.out.println("⏭️ 副厂长无权限审批 " + request.getLeaveDays() + " 天请假,转交厂长");

return nextHandler != null && nextHandler.handleRequest(request);

}

}

/**

* 厂长审批处理器

* 处理所有请假,是责任链的终点

*/

class ManagerHandler implements ApprovalHandler {

private ApprovalHandler nextHandler;

@Override

public void setNextHandler(ApprovalHandler nextHandler) {

// 厂长是最终审批人,没有下一个处理器

}

@Override

public boolean handleRequest(LeaveRequest request) {

System.out.println("厂长正在审批 " + request.getEmployeeName() + " 的请假申请...");

if (request.getLeaveDays() <= 10) {

System.out.println("✅ 厂长批准 " + request.getEmployeeName() + " 请假 " +

request.getLeaveDays() + " 天,原因:" + request.getReason());

return true;

} else {

System.out.println("❌ 厂长拒绝 " + request.getEmployeeName() + " 的请假申请," +

"原因:请假天数过长");

return false;

}

}

}

/**

* 审批链构建器

* 负责构建审批责任链

*/

class ApprovalChainBuilder {

/**

* 构建完整的审批责任链

* @return 责任链的起始处理器

*/

public static ApprovalHandler buildChain() {

// 创建各个处理器

ApprovalHandler groupLeader = new GroupLeaderHandler();

ApprovalHandler squadLeader = new SquadLeaderHandler();

ApprovalHandler viceManager = new ViceManagerHandler();

ApprovalHandler manager = new ManagerHandler();

// 构建责任链:组长 -> 班长 -> 副厂长 -> 厂长

groupLeader.setNextHandler(squadLeader);

squadLeader.setNextHandler(viceManager);

viceManager.setNextHandler(manager);

return groupLeader;

}

}

/**

* 请假服务类

* 提供请假申请服务

*/

class LeaveService {

private ApprovalHandler approvalHandler;

public LeaveService() {

this.approvalHandler = ApprovalChainBuilder.buildChain();

}

/**

* 提交请假申请

* @param request 请假请求

* @return 审批结果

*/

public boolean submitLeaveRequest(LeaveRequest request) {

System.out.println("\n=== " + request.getEmployeeName() + " 提交请假申请 ===");

System.out.println("请假天数:" + request.getLeaveDays() + " 天");

System.out.println("请假原因:" + request.getReason());

return approvalHandler.handleRequest(request);

}

}

/**

* 责任链模式演示类

*/

public class ChainOfResponsibilityPatternDemo {

public static void main(String[] args) {

LeaveService leaveService = new LeaveService();

// 测试不同天数的请假申请

System.out.println("===== 责任链模式 - 请假审批演示 =====");

// 1天请假 - 组长审批

LeaveRequest request1 = new LeaveRequest("张三", 1, "身体不适");

leaveService.submitLeaveRequest(request1);

// 2天请假 - 班长审批

LeaveRequest request2 = new LeaveRequest("李四", 2, "家里有事");

leaveService.submitLeaveRequest(request2);

// 3天请假 - 副厂长审批

LeaveRequest request3 = new LeaveRequest("王五", 3, "年假休息");

leaveService.submitLeaveRequest(request3);

// 5天请假 - 厂长审批

LeaveRequest request4 = new LeaveRequest("赵六", 5, "婚假");

leaveService.submitLeaveRequest(request4);

// 15天请假 - 厂长拒绝

LeaveRequest request5 = new LeaveRequest("钱七", 15, "长假旅游");

leaveService.submitLeaveRequest(request5);

}

}

责任链模式优势

降低耦合度:请求发送者无需知道具体的处理者

动态配置:可以动态地添加、删除或修改处理链

灵活性:可以改变处理链的顺序或结构

单一职责:每个处理者只关注自己的处理逻辑

3. 模板模式 (Template Pattern)

模式介绍

模板模式定义了一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

核心思想

封装不变部分:将不变的行为移到父类

扩展可变部分:将变化的行为由子类实现

代码复用:公共的代码在父类中实现

控制子类扩展:通过模板方法控制子类的扩展点

适用场景

有多个类包含相同的操作,但其中某些步骤的实现不同

需要控制子类扩展时,只允许在特定点进行扩展

重要的复杂算法需要定义骨架,细节由子类实现

经典示例:饮料制作系统

/**

* 抽象饮料类 - 模板类

* 定义饮料制作的基本流程

*/

abstract class BeverageTemplate {

/**

* 模板方法 - 定义饮料制作的完整流程(final防止子类重写)

*/

public final void prepareBeverage() {

boilWater(); // 煮沸水

brew(); // 冲泡(由子类实现)

pourInCup(); // 倒入杯子

addCondiments(); // 添加调料(由子类实现)

// 钩子方法 - 子类可以选择性重写

if (customerWantsCondiments()) {

extraStep(); // 额外步骤

}

serve(); // 上饮料

}

/**

* 煮沸水 - 具体方法(所有饮料都需要煮沸水)

*/

private void boilWater() {

System.out.println("1. 🚰 煮沸水");

}

/**

* 倒入杯子 - 具体方法(所有饮料都需要倒入杯子)

*/

private void pourInCup() {

System.out.println("3. 🥤 倒入杯子");

}

/**

* 上饮料 - 具体方法(所有饮料都需要上桌)

*/

private void serve() {

System.out.println("6. 🍹 上饮料:" + getBeverageName());

}

/**

* 钩子方法 - 客户是否想要调料(默认返回true,子类可重写)

*/

protected boolean customerWantsCondiments() {

return true;

}

/**

* 额外步骤 - 钩子方法(默认空实现,子类可重写)

*/

protected void extraStep() {

// 默认不执行额外步骤

}

/**

* 冲泡方法 - 抽象方法(必须由子类实现)

*/

protected abstract void brew();

/**

* 添加调料 - 抽象方法(必须由子类实现)

*/

protected abstract void addCondiments();

/**

* 获取饮料名称 - 抽象方法(必须由子类实现)

*/

protected abstract String getBeverageName();

}

/**

* 茶类 - 具体模板

* 实现茶的具体制作步骤

*/

class Tea extends BeverageTemplate {

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/8 5:25:09

关于图灵停机问题不可判定性证明

什么是图灵停机问题概念&#xff1a;图灵停机问题&#xff08;Halting Problem&#xff09;是否可判定&#xff0c;形式化而言&#xff1a;停机不停机对角线证明对角线&#xff0c;实际上逻辑系统中的符号完备问题也是通过该法构造解答的由于所有的图灵机都可以由 序列编码&…

作者头像 李华
网站建设 2026/4/7 9:55:40

回溯算法--总结1

第一周总结回溯问题抽象为树形结构&#xff0c;可以直观的看出其搜索的过程&#xff1a;for循环横向遍历&#xff0c;递归纵向遍历&#xff0c;回溯不断调整结果集。回溯算法三部曲&#xff1a;参数。终止条件。单层递归逻辑。剪枝&#xff1a;剪枝1&#xff1a;for循环在寻找起…

作者头像 李华
网站建设 2026/4/2 6:40:12

AI助力WSL2安装Ubuntu:自动解决常见错误

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个WSL2安装Ubuntu的AI辅助工具&#xff0c;要求实现以下功能&#xff1a;1.自动检测Windows系统版本和WSL2支持状态 2.智能选择最适合的Ubuntu版本 3.自动处理安装过程中的常…

作者头像 李华
网站建设 2026/3/30 7:18:56

AI如何优化Apache Airflow工作流编排

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个基于Apache Airflow的智能工作流编排系统&#xff0c;集成AI模型来自动生成优化的DAG结构&#xff0c;根据历史执行数据预测任务执行时间并动态调整调度策略。系统应包含任…

作者头像 李华
网站建设 2026/4/8 14:36:45

SpringBoot+MyBatisPlus入门:10分钟搭建第一个应用

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个最简单的SpringBootMyBatisPlus入门示例&#xff0c;要求&#xff1a;1. 使用Spring Initializr创建项目&#xff1b;2. 添加MyBatisPlus依赖&#xff1b;3. 创建Student实…

作者头像 李华
网站建设 2026/4/8 11:45:09

2、深入探索Shell输入、输出与吞吐量

深入探索Shell输入、输出与吞吐量 1. 位置参数与特殊参数 在Shell脚本中,位置参数是非常重要的概念。Bourne shell 只能处理最多 9 个位置参数,如果脚本中使用 $10 ,它会被解释为 $1 后面跟着一个零。为了兼容旧脚本,bash 保留了这种行为。若要访问大于 9 的位置参数…

作者头像 李华