文章

设计模式解密:深入理解责任链模式

模式定义

责任链模式(Chain of Responsibility)是一种行为型设计模式,允许你将请求沿着处理链传递。每个处理器对象决定是否处理请求以及是否将请求传递给链中的下一个处理器。

核心思想

  1. 解耦发送者与接收者:请求发送者不需要知道具体由哪个对象处理

  2. 动态组合处理链:可以灵活调整处理器的顺序和组合

  3. 多处理器协作:多个对象都有机会处理请求

适用场景

  • 多级审批流程(如请假审批)

  • 请求需要被多个对象处理

  • 需要动态指定请求处理对象集合

  • Web中间件处理(如身份验证、日志记录)

模式结构

  • Handler:定义处理请求的接口

  • ConcreteHandler:具体处理实现类

  • Client:组装责任链并触发请求

PHP实现示例:请假审批系统

<?php
// 抽象处理器
abstract class Handler {
    protected $nextHandler;

    public function setNext(Handler $handler): Handler {
        $this->nextHandler = $handler;
        return $handler;
    }

    abstract public function handleRequest(int $days);
}

// 具体处理器:组长
class TeamLeader extends Handler {
    public function handleRequest(int $days) {
        if ($days <= 2) {
            echo "组长批准{$days}天请假\n";
        } elseif ($this->nextHandler) {
            $this->nextHandler->handleRequest($days);
        } else {
            echo "{$days}天请假无法处理\n";
        }
    }
}

// 具体处理器:经理
class Manager extends Handler {
    public function handleRequest(int $days) {
        if ($days <= 5) {
            echo "经理批准{$days}天请假\n";
        } elseif ($this->nextHandler) {
            $this->nextHandler->handleRequest($days);
        } else {
            echo "{$days}天请假无法处理\n";
        }
    }
}

// 具体处理器:HR总监
class HRDirector extends Handler {
    public function handleRequest(int $days) {
        if ($days <= 15) {
            echo "HR总监批准{$days}天请假\n";
        } else {
            echo "超过15天请假需要董事会审批\n";
        }
    }
}

// 客户端使用
$leader = new TeamLeader();
$manager = new Manager();
$director = new HRDirector();

$leader->setNext($manager)->setNext($director);

$leader->handleRequest(1);  // 组长批准
$leader->handleRequest(4);  // 经理批准
$leader->handleRequest(10); // HR总监批准
$leader->handleRequest(20); // 需要董事会审批

Go实现示例:日志处理链

package main

import "fmt"

// 处理器接口
type Handler interface {
	Handle(level int, message string)
	SetNext(h Handler)
}

// 基础处理器结构
type BaseHandler struct {
	next Handler
}

func (b *BaseHandler) SetNext(h Handler) {
	b.next = h
}

// 具体处理器:控制台输出
type ConsoleHandler struct {
	BaseHandler
}

func (c *ConsoleHandler) Handle(level int, message string) {
	if level <= 2 {
		fmt.Printf("[Console] %s\n", message)
	} else if c.next != nil {
		c.next.Handle(level, message)
	}
}

// 具体处理器:文件记录
type FileHandler struct {
	BaseHandler
}

func (f *FileHandler) Handle(level int, message string) {
	if level <= 5 {
		fmt.Printf("[File] %s\n", message)
	} else if f.next != nil {
		f.next.Handle(level, message)
	}
}

// 具体处理器:邮件报警
type EmailHandler struct {
	BaseHandler
}

func (e *EmailHandler) Handle(level int, message string) {
	if level >= 8 {
		fmt.Printf("[Email Alert] %s\n", message)
	} else if e.next != nil {
		e.next.Handle(level, message)
	}
}

func main() {
	console := &ConsoleHandler{}
	file := &FileHandler{}
	email := &EmailHandler{}

	console.SetNext(file)
	file.SetNext(email)

	// 模拟不同级别的日志
	console.Handle(1, "Debug info")
	console.Handle(3, "Warning message")
	console.Handle(6, "Error occurred")
	console.Handle(9, "System critical!")
}

/* 输出:
[Console] Debug info
[File] Warning message
[File] Error occurred
[Email Alert] System critical!
*/

模式优缺点

优点

  • 符合单一职责原则

  • 符合开闭原则

  • 动态调整处理流程

  • 降低耦合度

缺点

  • 请求可能未被处理

  • 影响性能(链过长时)

  • 调试复杂度增加

不同语言实现差异

特性

PHP

Go

继承机制

类继承

结构体组合

接口实现

显式声明implements

隐式实现interface

链式调用

通过返回$this实现

需要显式设置next

典型应用场景

Web中间件、审批系统

中间件、日志处理链

总结

责任链模式通过将多个处理对象连接成链,实现了请求处理与对象解耦。当系统需要多个对象处理同一请求,且处理对象可能动态变化时,该模式能显著提高系统灵活性。不同语言实现的核心思想一致,但在具体语法和实现方式上会根据语言特性有所不同。

掌握责任链模式的关键在于理解"处理传递"的机制,以及如何合理设计处理对象的判断逻辑。在实际开发中,可以结合其他模式(如模板方法模式)来构建更强大的处理体系。

License:  CC BY 4.0