新增责任链模式示例
This commit is contained in:
parent
ed4190e944
commit
899772115c
147
chain/chain.go
Normal file
147
chain/chain.go
Normal 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
33
chain/chain_test.go
Normal 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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user