这里我们使用责任链模式来创建一个参数校验的示例。在这个示例中,我们将实现一个简单的责任链来校验不同的参数条件。这种模式允许我们将多个校验步骤串联在一起,以便可以在不同的条件下进行灵活的校验。
设计思路
-
接口定义 (
Validator
)- 目的:定义责任链中每个节点的基本行为。
- 设计思想 :接口包含三个方法:
Validate(params *Params) error
:执行具体的校验逻辑。SetNext(v Validator) Validator
:设置链中的下一个校验节点,实现链式调用。Execute(params *Params) error
:执行当前节点的Validate
方法,并继续执行链中的下一个节点。
-
复用机制 (
BaseValidator
)- 目的:通过合成复用来实现校验链的连接机制。
- 设计思想 :
BaseValidator
是一个可复用的结构体,包含nextValidator
字段(用于指向链中的下一个校验节点)和实现SetNext
、Execute
方法。任何实现了Validator
接口的结构体都可以通过嵌入BaseValidator
来获得这些方法。
-
具体校验器
- 目的:每个校验器负责校验请求中的某一特定参数。
- 设计思想 :
- 例如,
NonEmptyValidator
用于检查字符串是否为空,PositiveNumberValidator
用于检查数字是否为正。 - 这些校验器通过嵌入
BaseValidator
来获得链式调用的能力。
- 例如,
-
链式调用
- 目的:通过链式调用初始化责任链,使代码结构清晰,增强可读性。
- 设计思想 :通过
SetNext
方法将各个校验器连接起来,使得责任链的逻辑关系一目了然。
-
扩展性
- 目的:轻松扩展系统功能,支持更多的校验逻辑。
- 设计思想:由于责任链是动态配置的,可以方便地添加、移除或重排校验器节点,而无需修改现有代码结构。
案例代码
以下是一个基于责任链模式的参数校验示例:
go
package main
import (
"errors"
"fmt"
)
// Validator 接口定义了校验器的基本行为
type Validator interface {
Validate(params *Params) error
SetNext(v Validator) Validator
Execute(params *Params) error
}
// BaseValidator 复用结构体,实现 Validator 接口的 SetNext 和 Execute 方法
type BaseValidator struct {
nextValidator Validator
}
// SetNext 设置下一个校验器
func (b *BaseValidator) SetNext(v Validator) Validator {
b.nextValidator = v
return v
}
// Execute 执行当前校验和后续校验
func (b *BaseValidator) Execute(params *Params) error {
if b.nextValidator != nil {
if err := b.nextValidator.Validate(params); err != nil {
return err
}
return b.nextValidator.Execute(params)
}
return nil
}
// Params 结构体包含需要校验的参数
type Params struct {
Name string
Age int
Email string
}
// NonEmptyValidator 校验字符串是否为空
type NonEmptyValidator struct {
BaseValidator
}
func (v *NonEmptyValidator) Validate(params *Params) error {
if params.Name == "" {
return errors.New("name cannot be empty")
}
return nil
}
// PositiveNumberValidator 校验数字是否为正
type PositiveNumberValidator struct {
BaseValidator
}
func (v *PositiveNumberValidator) Validate(params *Params) error {
if params.Age <= 0 {
return errors.New("age must be a positive number")
}
return nil
}
// EmailFormatValidator 校验邮件格式(简单示例)
type EmailFormatValidator struct {
BaseValidator
}
func (v *EmailFormatValidator) Validate(params *Params) error {
if params.Email == "" || !contains(params.Email, "@") {
return errors.New("invalid email format")
}
return nil
}
// contains 是一个简单的字符串包含判断函数
func contains(s, substr string) bool {
return len(s) >= len(substr) && (s[:len(substr)] == substr || contains(s[1:], substr))
}
func main() {
params := &Params{
Name: "John Doe",
Age: 30,
Email: "johndoe@example.com",
}
// 初始化校验链
validator := &NonEmptyValidator{}
validator.SetNext(&PositiveNumberValidator{}).
SetNext(&EmailFormatValidator{})
// 执行校验
err := validator.Execute(params)
if err != nil {
fmt.Println("Validation failed:", err)
} else {
fmt.Println("Validation succeeded")
}
}