新增责任链模式示例

This commit is contained in:
fantasticbin 2025-07-05 19:57:35 +08:00
parent ed4190e944
commit 899772115c
2 changed files with 180 additions and 0 deletions

147
chain/chain.go Normal file
View File

@ -0,0 +1,147 @@
package chain
import (
"errors"
"fmt"
)
const (
PatientStatusStart = iota + 1 // 状态:开始看病
PatientStatusReception // 状态:已挂号
PatientStatusClinic // 状态:已看诊
PatientStatusCashier // 状态:已缴费
PatientStatusPharmacy // 状态:已拿药
)
type Patient struct {
name string // 姓名
status int // 状态
}
type PatientHandler interface {
Execute(patient *Patient) error // 处理链路传递
SetNext(handler PatientHandler) PatientHandler // 设置下一个处理者
Do(patient *Patient) error // 执行处理逻辑
}
// BaseHandler 充当抽象类的角色
// Do 方法无法抽象出来,故不实现
type BaseHandler struct {
nextHandler PatientHandler // 下一个处理者
}
func (h *BaseHandler) Execute(patient *Patient) error {
if patient == nil {
return nil
}
// 因为 Do 方法未实现,这里无法调用自身的 Do
// 实际调用链路时,需要为初始流程定义一个起始执行者
if h.nextHandler != nil {
if err := h.nextHandler.Do(patient); err != nil { // 调用下一个处理者的Do方法
return err
}
return h.nextHandler.Execute(patient) // 调用下一个处理者的Execute方法
}
return nil
}
func (h *BaseHandler) SetNext(handler PatientHandler) PatientHandler {
h.nextHandler = handler
return handler
}
type Reception struct {
BaseHandler // 嵌入BaseHandler以实现链式调用
}
func (r *Reception) Do(patient *Patient) error {
if patient.status > PatientStatusStart {
return errors.New("患者已经挂号")
}
fmt.Printf("挂号处为患者 %s 挂号\n", patient.name)
patient.status = PatientStatusReception // 更新患者状态为已挂号
return nil
}
type Clinic struct {
BaseHandler // 嵌入BaseHandler以实现链式调用
}
func (c *Clinic) Do(patient *Patient) error {
if patient.status == PatientStatusStart {
return errors.New("患者还未挂号")
}
if patient.status > PatientStatusReception {
return errors.New("患者已经完成医生诊断")
}
fmt.Printf("医生为患者 %s 进行诊断\n", patient.name)
patient.status = PatientStatusClinic // 更新患者状态为已看诊
return nil
}
type Cashier struct {
BaseHandler // 嵌入BaseHandler以实现链式调用
}
func (c *Cashier) Do(patient *Patient) error {
if patient.status < PatientStatusClinic {
return errors.New("患者还未看诊")
}
if patient.status > PatientStatusClinic {
return errors.New("患者已经完成缴费")
}
fmt.Printf("收费处收取患者 %s 的费用\n", patient.name)
patient.status = PatientStatusCashier // 更新患者状态为已缴费
return nil
}
type Pharmacy struct {
BaseHandler // 嵌入BaseHandler以实现链式调用
}
func (p *Pharmacy) Do(patient *Patient) error {
if patient.status < PatientStatusCashier {
return errors.New("患者还未缴费")
}
if patient.status > PatientStatusCashier {
return errors.New("患者已经领取药物")
}
fmt.Printf("药房为患者 %s 配药\n", patient.name)
patient.status = PatientStatusPharmacy // 更新患者状态为已拿药
return nil
}
type HospitalChainHandler struct {
BaseHandler // 嵌入BaseHandler以实现链式调用
}
// Do 该方法可无逻辑,如需执行逻辑则需要重写 Execute 来确保执行
func (h *HospitalChainHandler) Do(patient *Patient) error {
fmt.Printf("患者 %s 开始看病\n", patient.name)
patient.status = PatientStatusStart // 更新患者状态为开始看病
return nil
}
// Execute 重写该方法以确保责任链的执行顺序
func (h *HospitalChainHandler) Execute(patient *Patient) error {
if patient == nil {
return nil
}
if err := h.Do(patient); err != nil { // 首先执行自己的Do方法
return err
}
return h.BaseHandler.Execute(patient) // 然后继续责任链
}

33
chain/chain_test.go Normal file
View File

@ -0,0 +1,33 @@
package chain
import "testing"
func TestChain(t *testing.T) {
// 创建患者实例
patient := &Patient{name: "张三"}
// 创建看病处理者链
hospital := &HospitalChainHandler{}
// 设置病人看病的链路
processes := []PatientHandler{
&Reception{},
&Clinic{},
&Cashier{},
&Pharmacy{},
}
var current PatientHandler = hospital
for _, process := range processes {
current = current.SetNext(process)
}
// 执行处理链
if err := hospital.Execute(patient); err != nil {
t.Errorf("处理患者失败: %v", err)
}
// 检查最终状态
if patient.status != PatientStatusPharmacy {
t.Errorf("患者状态不正确,期望 %d实际 %d", PatientStatusPharmacy, patient.status)
}
}