Go 设计模式:责任链和函数选项,让你的代码更优雅!

最近接触到越来越多有历史 “沉淀” 的 Go 项目,深感设计模式和及时干预的重要性。近期会分享一些设计模式,一起学习代码设计!

今天的分享的设计模式是:责任链和函数选项模式。在日常程序里是比较常用的。很多开源库中也有使用。

责任链模式

责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许对象将请求沿处理程序链进行传递。

程序链既可以处理请求,也可以继续将请求传递给链中的下一个处理程序。请求沿着处理程序链传递,直到请求被处理或到达处理程序链的末端。

这类场景的例子包括:事件处理、日志记录和错误处理等类似拦截器注入的用法。

例子

我们将会创建一个简单例子来演示 Go 中的责任链模式。

在这个例子中,责任链将负责验证请求、打印错误日志和处理请求本身。

具体代码如下:

package service

import "fmt"

type Service interface {
    HelloWorld(name string) (string, error)
}

type service struct {}

func (s service) HelloWorld(name string) (string, error) {
    return fmt.Sprintf("Hello World from %s", name), nil
}

type validator struct {
    next Service
}

func (v validator) HelloWorld(name string) (string, error) {
    if len(name) <= 3 {
        return "", fmt.Errorf("name length must be greater than 3")
    }

    return v.next.HelloWorld(name)
}

type logger struct {
    next Service
}

func (l logger) HelloWorld(name string) (string, error) {
    res, err := l.next(name)

    if err != nil {
        fmt.Println("error:", err)
        return res, err
    }

    fmt.Println("HelloWorld method executed successfuly")
    return res, err
}

func New() Service {
    return logger{
        next: validator {
            next: service{},
        },
    }
}

入口 main 函数使用:

package main

import (
    "fmt"
    "service"
)

func main() {
    s := service.New()

    res, err := s.HelloWorld("煎鱼")
    fmt.Println(res, err) // Hello World from 煎鱼

    res, err := s.HelloWorld("edd")
    fmt.Println(res, err) // name length must be greater than 3
}

在本例中,我们创建了一个实现 Service 接口的简单服务。Service 接口定义了一个方法 HelloWorld,该方法将名称作为参数,并返回一条 Hello World 信息。

我们还创建了两个额外的结构体 validatorlogger,它们都实现了 Service 接口。

validator 结构会验证名称的长度,如果长度小于或等于 3,则返回错误信息。当 HelloWorld 方法成功执行时,logger 结构会打印错误日志和成功信息。

New 函数通过将 validatorlogger 结构与 Service 结构链起来,创建了一个处理程序链。

Service 结构体的方法是链中的最后一个处理程序,如果请求通过验证,它将处理请求。

例子中 next 字段的作用是什么

next 字段用于保存链中的下一个处理程序。

当在一个处理程序上调用 HelloWorld 方法时,会使用 next 字段在链中的下一个处理程序上调用 HelloWorld 方法。

对照看可以得知,validatorlogger 结构体中的 next 字段,是用于链式处理程序的关键字段。

函数选项模式

函数选项模式(Function Options Pattern)是一种很常见的设计模式,它允许开发人员通过使用 Options 作为参数,为函数或方法提供灵活且可定制的行为。

常用于 Go 库和框架,为用户提供简洁明了的 API。经常在我们使用的基础库能看到,例如:grpc-go。

例子

我们有一个用 Go 表示 HTTP 服务器的 Server 结构体作为基础。

我们希望为用户提供配置 HTTP Server 各方面的功能,例如:监听的端口、超时时间以及是否启用日志记录等。

具体代码如下:

package main

import "fmt"

type Server struct {
    Host     string
    Port     int
    Protocol string
    Timeout  int
}

type ServerOption func(*Server)

func WithHost(host string) ServerOption {
    return func(s *Server) {
        s.Host = host
    }
}

func WithPort(port int) ServerOption {
    return func(s *Server) {
        s.Port = port
    }
}

func WithProtocol(protocol string) ServerOption {
    return func(s *Server) {
        s.Protocol = protocol
    }
}

func WithTimeout(timeout int) ServerOption {
    return func(s *Server) {
        s.Timeout = timeout
    }
}

func NewServer(options ...ServerOption) *Server {
    server := &Server{
        Host:     "localhost",
        Port:     8080,
        Protocol: "http",
        Timeout:  30,
    }

    for _, option := range options {
        option(server)
    }

    return server
}

func main() {
    server := NewServer(
        WithHost("eddycjy.com"),
        WithPort(9000),
        WithProtocol("https"),
        WithTimeout(60),
    )

    fmt.Printf("Server: %+v\n", server)
}

解决了什么问题

  • 参数数量不断增加:随着参数数量的增加,传统的函数签名可能会变得臃肿不堪。函数选项模式允许添加新的选项,而无需更改函数签名或破坏现有代码。

  • 可读性:当一个函数需要多个参数,尤其是同一类型的参数时,很难记住每个参数的顺序和含义。有了函数选项(Option),每个选项都有清晰的标签,不言自明,从而提高了代码的可读性。

  • 缺省值:函数选项模式允许你轻松地为选项提供默认值。如果在调用函数时没有提供选项,就会使用默认值。

  • 可选参数:在某些情况下,你可能想让某些参数成为可选参数。函数选项模式可以让你轻松做到这一点,并提供一个灵活的接口。

  • 封装和独立:每个选项都是一个函数,可以包含自己的程序逻辑。这样就可以封装每个选项的逻辑,并保持主函数简洁明了。

总结

一个好的设计模式,可以让你的项目更具有易读性。程序编写和使用起来更加的舒心。今天给大家介绍的责任链模式和函数可选模式,是非常常用的。

推荐大家可以尝试应用到自己的 Go 项目中去,想必会有非常大的帮助!

推荐阅读

关注和加煎鱼微信,

一手消息和知识,拉你进技术交流群👇

18dc6f9c34a1d1a24bfe0e0ca5a31aaa.jpeg

2f511e3c9ccdeadb1fe0db107e8070f0.png

你好,我是煎鱼,出版过 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路

日常分享高质量文章,输出 Go 面试、工作经验、架构设计,加微信拉读者交流群,和大家交流!

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值