【最佳实践】Go 责任链模式实现参数校验

这里我们使用责任链模式来创建一个参数校验的示例。在这个示例中,我们将实现一个简单的责任链来校验不同的参数条件。这种模式允许我们将多个校验步骤串联在一起,以便可以在不同的条件下进行灵活的校验。

设计思路

  1. 接口定义 (Validator)

    • 目的:定义责任链中每个节点的基本行为。
    • 设计思想 :接口包含三个方法:
      • Validate(params *Params) error:执行具体的校验逻辑。
      • SetNext(v Validator) Validator:设置链中的下一个校验节点,实现链式调用。
      • Execute(params *Params) error:执行当前节点的 Validate 方法,并继续执行链中的下一个节点。
  2. 复用机制 (BaseValidator)

    • 目的:通过合成复用来实现校验链的连接机制。
    • 设计思想BaseValidator 是一个可复用的结构体,包含 nextValidator 字段(用于指向链中的下一个校验节点)和实现 SetNextExecute 方法。任何实现了 Validator 接口的结构体都可以通过嵌入 BaseValidator 来获得这些方法。
  3. 具体校验器

    • 目的:每个校验器负责校验请求中的某一特定参数。
    • 设计思想
      • 例如,NonEmptyValidator 用于检查字符串是否为空,PositiveNumberValidator 用于检查数字是否为正。
      • 这些校验器通过嵌入 BaseValidator 来获得链式调用的能力。
  4. 链式调用

    • 目的:通过链式调用初始化责任链,使代码结构清晰,增强可读性。
    • 设计思想 :通过 SetNext 方法将各个校验器连接起来,使得责任链的逻辑关系一目了然。
  5. 扩展性

    • 目的:轻松扩展系统功能,支持更多的校验逻辑。
    • 设计思想:由于责任链是动态配置的,可以方便地添加、移除或重排校验器节点,而无需修改现有代码结构。

案例代码

以下是一个基于责任链模式的参数校验示例:

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")
	}
}
相关推荐
云飞云共享云桌面14 分钟前
广东精密机械设备工厂8-10人共享一台SolidWorks设计服务器
运维·服务器·3d·自动化·汽车·制造
jieyucx24 分钟前
【高级利用】条件竞争与逻辑漏洞:与服务器赛跑的艺术
android·运维·服务器·web安全·文件上传
tianyuanwo30 分钟前
服务器OS组件研发效能度量可视系统——顶层方案设计与阶段性规划
运维·服务器·度量系统
初级炼丹师(爱说实话版)40 分钟前
Ubuntu服务器配置docker
服务器·ubuntu·docker
机建狂魔1 小时前
Codex 接入第三方模型 API 实战:以 Mimo 为例
java·服务器·数据库·ai·ai编程·codex
土星云SaturnCloud2 小时前
智慧温室精准环控:土星云边缘计算设备实现温光水肥本地闭环调节
服务器·人工智能·ai·边缘计算
Awna2 小时前
Golang 大小写可见性规范
开发语言·后端·golang
深爱水瓶 血影S狂风2 小时前
函数调用过程探究
linux·运维·服务器
酷可达拉斯3 小时前
Linux操作系统-磁盘空间使用率100%如何处理?
linux·运维·服务器·云计算·bash
神秘的MT3 小时前
C# WinForm Socket 服务器 + 串口转发
服务器·网络·学习·c#