软件设计模式系列之十五——职责链模式
1 模式的定义
职责链模式(Chain of Responsibility Pattern)也称为责任链模式,是一种结构型设计模式,用于构建一条对象处理请求的责任链。在这个模式中,多个对象依次处理请求,直到其中一个对象能够处理该请求为止。职责链模式将请求的发送者和接收者解耦,允许多个对象都有机会处理请求,同时可以动态地配置责任链的顺序和组成。
职责链模式的核心思想是将请求沿着一条链传递,每个处理者都可以选择处理请求或将其传递给下一个处理者。这种方式类似于实现一个处理管道,每个管道元素可以选择执行任务或将任务传递给下一个元素。
2 举例说明
为了更好地理解职责链模式,让我们考虑一个实际的例子。审批系统。假设在一个公司中,员工可以提交报销申请,然后需要一系列审批人员逐级审批,包括直属领导、部门总监、人事部门、高层领导。每个审批人员都在自己的权限内考虑是否签字,签完之后将会继续传递给下一级审批人员。这种情况下,可以使用职责链模式来构建一个审批流程。
在这个示例中,每个审批人员都是责任链中的一个节点,他们可以选择批准或拒绝请求,并将请求传递给下一个审批人员,直到有人批准或拒绝为止。
3 结构
职责链模式的结构包括以下几个关键部分:
Handler(处理者):定义一个处理请求的接口,并包含一个指向下一个处理者的引用。处理者可以选择处理请求或将其传递给下一个处理者。
ConcreteHandler(具体处理者):实现处理请求的具体逻辑,如果自己无法处理请求,就将请求传递给下一个处理者。
Client(客户端):创建责任链并将请求发送到责任链的第一个处理者。客户端不需要知道责任链的具体结构,只需将请求发送给第一个处理者即可。
4 实现步骤
实现职责链模式时,通常遵循以下步骤:
定义处理请求的接口(Handler),并在接口中声明处理请求的方法。
创建具体处理者类(ConcreteHandler),实现处理请求的具体逻辑。每个具体处理者都需要包含一个指向下一个处理者的引用。
在具体处理者类中,实现处理请求的逻辑,并在必要时将请求传递给下一个处理者。
在客户端代码中创建责任链,并将请求发送给责任链的第一个处理者。
5 代码实现
现在,让我们通过 Java 代码来实现审批系统的职责链模式。
// 1. 定义处理请求的接口
interface Approver {
void approveRequest(ExpenseRequest request);
}
// 2. 创建具体处理者类
class TeamLeader implements Approver {
private Approver nextApprover;
@Override
public void approveRequest(ExpenseRequest request) {
if (request.getAmount() <= 100) {
System.out.println("Team Leader approved the expense request.");
} else if (nextApprover != null) {
nextApprover.approveRequest(request);
}
}
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
}
class Manager implements Approver {
private Approver nextApprover;
@Override
public void approveRequest(ExpenseRequest request) {
if (request.getAmount() <= 500) {
System.out.println("Manager approved the expense request.");
} else if (nextApprover != null) {
nextApprover.approveRequest(request);
}
}
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
}
class FinanceDepartment implements Approver {
@Override
public void approveRequest(ExpenseRequest request) {
System.out.println("Finance Department approved the expense request.");
}
}
// 3. 客户端代码
public class Client {
public static void main(String[] args) {
Approver teamLeader = new TeamLeader();
Approver manager = new Manager();
Approver finance = new FinanceDepartment();
// 构建责任链
teamLeader.setNextApprover(manager);
manager.setNextApprover(finance);
// 提交报销请求
ExpenseRequest request1 = new ExpenseRequest("John", 80);
teamLeader.approveRequest(request1);
ExpenseRequest request2 = new ExpenseRequest("Alice", 300);
teamLeader.approveRequest(request2);
ExpenseRequest request3 = new ExpenseRequest("Bob", 800);
teamLeader.approveRequest(request3);
}
}
6 典型应用场景
职责链模式在实际应用中有多种典型场景,以下是一些常见的应用。
审批流程:如报销审批、请假审批等,不同级别的审批人员构成责任链,依次处理请求。
事件处理:在图形用户界面(GUI)开发中,事件处理机制可以采用职责链模式,将事件从用户界面传递给各种控件,以便处理用户输入。
日志记录:不同级别的日志记录器可以组成责任链,根据日志级别决定是否记录日志以及如何记录。
异常处理:在程序中处理异常时,可以使用职责链模式来处理不同类型的异常,以便根据异常类型采取不同的处理策略。
权限控制:在系统中控制用户访问权限时,可以使用职责链模式来构建权限控制链,根据用户的权限级别逐级检查并授权。
HTTP请求处理:Web框架中的中间件(Middleware)可以使用职责链模式来处理HTTP请求,例如身份验证、日志记录、缓存等中间件可以依次处理请求。
7 优缺点
优点:
松耦合:职责链模式将请求的发送者和接收者解耦,允许多个对象都有机会处理请求,使系统更加灵活。
动态配置责任链:责任链的顺序和组成可以在运行时动态配置,不需要修改代码即可调整责任链。
可扩展性:可以轻松地添加新的处理者类,扩展责任链,不会影响现有代码。
缺点:
性能问题:如果责任链过长或者处理请求的逻辑复杂,可能会导致性能问题,因为每个请求都需要遍历整个责任链。
请求未处理:如果责任链没有正确配置或者没有合适的处理者来处理请求,可能导致请求无法被处理。
难以调试:责任链模式中,请求的处理路径可能会变得不透明,难以调试和理解。
8 类似模式
与职责链模式类似的模式包括策略模式、装饰器模式和命令模式。这些模式都有一定的相似之处,但它们各自有不同的关注点和应用场景。
策略模式(Strategy Pattern):
策略模式和职责链模式都允许动态地选择不同的对象来处理请求或任务。它们都关注于将请求发送者和接收者解耦,使系统更加灵活。策略模式关注于选择不同的算法或策略来处理特定的任务,它将不同的策略封装成独立的对象,并允许在运行时切换策略。职责链模式关注于多个对象依次处理请求,直到其中一个对象能够处理为止,每个对象都有机会处理请求。
装饰器模式(Decorator Pattern):
装饰器模式和职责链模式都允许动态地包装对象以增强其功能。它们都通过组合来实现,可以链式地将多个装饰器或处理者组合在一起。装饰器模式关注于在不改变接口的情况下增强对象的功能,通常用于为单个对象添加功能。职责链模式关注于将请求从一个对象传递到另一个对象,每个对象都可以选择处理或传递请求。
命令模式(Command Pattern):
命令模式和职责链模式都可以用于将请求的发送者和接收者解耦。它们都关注于将请求封装成对象,允许将请求传递给不同的对象。命令模式关注于将请求封装成命令对象,允许撤销和重做操作,以及延迟执行请求。职责链模式关注于多个对象依次处理请求,直到其中一个对象能够处理为止,不一定涉及命令的封装和执行。
总的来说,这些模式有一些共同之处,包括解耦请求的发送者和接收者,以及支持动态配置和组合对象。然而,它们的关注点和应用场景不同,应根据具体需求来选择合适的模式。在一些情况下,这些模式甚至可以组合使用,以实现更复杂的功能。
9 小结
职责链模式是一种有用的设计模式,它可以帮助构建灵活的责任链,使多个对象能够依次处理请求。通过将请求的发送者和接收者解耦,职责链模式可以实现松耦合的设计,允许在运行时动态配置责任链的顺序和组成。然而,需要注意在设计时考虑性能问题,确保责任链不会过长或过于复杂。职责链模式在实际应用中有多种典型场景,包括审批流程、事件处理、日志记录等。希望本文能够帮助你更好地理解和应用职责链模式。