索引

https://waterflow.link/articles/1663835071801

当我在使用go-zero时,我看到了好多像下面这样的代码:

...

type (
// RunOption defines the method to customize a Server.
RunOption func(*Server) // A Server is a http server.
Server struct {
ngin *engine
router httpx.Router
}
) ... // AddRoutes add given routes into the Server.
func (s *Server) AddRoutes(rs []Route, opts ...RouteOption) {
r := featuredRoutes{
routes: rs,
}
for _, opt := range opts {
opt(&r)
}
s.ngin.addRoutes(r)
} ... // WithJwt returns a func to enable jwt authentication in given route.
func WithJwt(secret string) RouteOption {
return func(r *featuredRoutes) {
validateSecret(secret)
r.jwt.enabled = true
r.jwt.secret = secret
}
}

我们可以把重点放在RouteOption上面。这里就使用了选项模式。

什么是选项模式?

选项模式是一种函数式编程模式,用于为可用于修改其行为的函数提供可选参数。

如果你用过php的话,你肯定会看到过这样的函数,毕竟PHP是世界上最好的语言:

public function cache(callable $callable, $duration = null, $dependency = null)

// 我们可以这样调用
cache($callable); // 也可以把后面的可选参数带上
cache($callable, $duration);

这种能力在 API 设计中非常有用,因为

  • 允许用户以最低配置使用方法,同时仍为有经验的用户提供充足的配置选项。
  • 允许开发者在不破坏向后兼容性的情况下添加新选项。

然而,在 Golang 中,这是不可能的。该语言不提供添加可选参数的方法。

这就是“选项模式”的用武之地。它允许用户在调用方法 时传递其他选项,然后可以相应地修改其行为。让我们看一个小例子。

假设我们有一个结构体Server,它有 3 个属性port, timeoutmaxConnections

type Server struct {
port string
timeout time.Duration
maxConnections int
}

然后我们有个Server的工厂方法

func NewServer(port string, timeout time.Duration, maxConnections int) *Server {
return &Server{
port: port,
timeout: timeout,
maxConnections: maxConnections,
}
}

但是现在我们希望只有端口号是必传的,timeoutmaxConnections成为可选参数。在很多情况下,这些的默认值就足够了。另外,我不想用这些不必要的配置来轰炸刚刚学习或试验我的 方法 的新用户。让我们看看该怎么去实现。

首先我们定义一个新的option结构体

type Option func(*Server)

Option是一个函数类型,它接受指向我们的Server. 这很重要,因为我们将使用这些选项修改我们的Server实例。

现在让我们定义我们的选项。惯例是在我们的选项前面加上 With,但可以随意选择适合您的域语言的任何名称

func WithTimeout(timeout time.Duration) Option {
return func(s *Server) {
s.timeout = timeout
}
} func WithMaxConnections(maxConn int) Option {
return func(s *Server) {
s.maxConnections = maxConn
}
}

我们的两个选项WithTimeoutWithMaxConnections,采用配置值并返回一个Option。这Option只是一个函数,它接受一个指向我们Server对象的指针并将所需的属性设置为提供的值。例如,WithTimeout获取超时持续时间,然后返回一个函数(其签名与 Option相同)将我们服务器的 timeout 属性设置为提供的值。

在这里,我们使用了一种几乎所有现代语言(包括 Golang)都支持的称为闭包的技术

我们的工厂方法Server现在需要修改以支持这种变化

func NewServer(port string, options ...Option) *Server {
server := &Server{
port: port,
} for _, option := range options {
option(server)
} return server
}

现在我们就可以用上面世界上最好的语言的方式调用了

NewServer("8430")
NewServer("8430", WithTimeout(10*time.Second))
NewServer("8430", WithTimeout(10*time.Second), WithMaxConnections(10))

在这里你可以看到我们的客户端现在可以创建一个只有端口的最小服务器,但如果需要也可以自由地提供更多的配置选项。

这种设计具有高度的可扩展性和可维护性,甚至比我们在 PHP 中看到的可选参数还要好。它允许我们添加更多选项,而不会膨胀我们的函数签名,也不会触及我们在工厂方法中的代码。

下面是完整代码:

package main

import "time"

type Option func(*Server)

type Server struct {
port string
timeout time.Duration
maxConnections int
} func NewServer(port string, options ...Option) *Server {
server := &Server{
port: port,
} for _, option := range options {
option(server)
} return server
} func WithTimeout(timeout time.Duration) Option {
return func(s *Server) {
s.timeout = timeout
}
} func WithMaxConnections(maxConn int) Option {
return func(s *Server) {
s.maxConnections = maxConn
}
} func main() {
NewServer("8430")
NewServer("8430", WithTimeout(10*time.Second))
NewServer("8430", WithTimeout(10*time.Second), WithMaxConnections(10))
}

golang中的选项模式的更多相关文章

  1. (13)ASP.NET Core 中的选项模式(Options)

    1.前言 选项(Options)模式是对配置(Configuration)的功能的延伸.在12章(ASP.NET Core中的配置二)Configuration中有介绍过该功能(绑定到实体类.绑定至对 ...

  2. 基于SqlSugar的开发框架循序渐进介绍(7)-- 在文件上传模块中采用选项模式【Options】处理常规上传和FTP文件上传

    在基于SqlSugar的开发框架的服务层中处理文件上传的时候,我们一般有两种处理方式,一种是常规的把文件存储在本地文件系统中,一种是通过FTP方式存储到指定的FTP服务器上.这种处理应该由程序进行配置 ...

  3. golang中逗号ok模式_转

    ,ok,第一个参数是一个值或者nil,第二个参数是true/false或者一个错误error.在一个需要赋值的if条件语句中,使用这种模式去检测第二个参数值会让代码显得优雅简洁.这种模式在go语言编码 ...

  4. asp.net core 3.0 选项模式1:使用

    本篇只是从应用角度来说明asp.net core的选项模式,下一篇会从源码来分析 1.以前的方式 以前我们使用web.config/app.config时是这样使用配置的 var count = Co ...

  5. Go语言设计模式之函数式选项模式

    Go语言设计模式之函数式选项模式 本文主要介绍了Go语言中函数式选项模式及该设计模式在实际编程中的应用. 为什么需要函数式选项模式? 最近看go-micro/options.go源码的时候,发现了一段 ...

  6. Go语言实践模式 - 函数选项模式(Functional Options Pattern)

    什么是函数选项模式 大家好,我是小白,有点黑的那个白. 最近遇到一个问题,因为业务需求,需要对接三方平台. 而三方平台提供的一些HTTP(S)接口都有统一的密钥生成规则要求. 为此我们封装了一个独立的 ...

  7. Golang 常见设计模式之选项模式

    熟悉 Python 开发的同学都知道,Python 有默认参数的存在,使得我们在实例化一个对象的时候,可以根据需要来选择性的覆盖某些默认参数,以此来决定如何实例化对象.当一个对象有多个默认参数时,这个 ...

  8. 安卓中的Model-View-Presenter模式介绍

    转载自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0425/2782.html 英文原文:Introduction to M ...

  9. 基础知识 - Golang 中的正则表达式

    ------------------------------------------------------------ Golang中的正则表达式 ------------------------- ...

随机推荐

  1. Spring源码 05 IOC 注解方式

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  2. Slf4j的MDC初尝试

    为什么会用到MDC? 本人使用Java两年时间,鉴于经验有限,在开发java后端代码过程中,为了定位问题,希望同一个线程的requestId可以从web层的日志一直输出到dao层,这样使用Linux命 ...

  3. Java SE 13 新增特性

    Java SE 13 新增特性 作者:Grey 原文地址:Java SE 13 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  4. CF662C Binary Table (快速沃尔什变换FWT)

    题面 题解 我们会发现,如果单独的一列或一行,它的答案是O1确定的,如果确定了每一行是否变换,那么最后的答案也就简单了许多, 如果确定了行的变换状压下来是x(即x的i位表示第i行是否变换,理解就行), ...

  5. KingbaseES V8R6备份恢复案例之--删除test数据库后sys_backup.sh备份

    案例说明: KingbaseES V8R6通过sys_backup.sh执行物理备份,默认sys_backup.sh执行备份初始化时,需要连接test数据库进行身份的认证:在一些生产环境为了安全需求, ...

  6. Linux云主机安全入侵排查步骤

    导语 经常有用户报障系统被植入恶意程序,如挖矿软件.ddos攻击病毒.syn映射攻击病毒等,可以按照以下流程为用户排查入侵病毒类型: 一.定位病毒进程 对于用户反馈云主机性能卡顿,CPU和内存占用较高 ...

  7. 使用Kali的wifite和aircrack-ng联合破解wifi密码

    准备材料 有kali的虚拟机,这里推荐VM 一个超级便宜的USB无线网卡,很便宜三十几块钱 一个靠谱的WPA密码字典(关于字典文件,我这里整理了好多,可联系我.QQ:1213456261) 1.运行k ...

  8. JAVA中方法的调用主要有以下几种

    JAVA中方法的调用主要有以下几种: 1.非静态方法 非静态方法就是没有 static 修饰的方法,对于非静态方法的调用,是通过对 象来调用的,表现形式如下. 对象名.方法() eg: public ...

  9. 统一建模语言UML---类图

    什么是统一建模语言,来看看百科中的介绍统一建模语言(Unified Modeling Language,UML)是一种为面向对象系统的产品进行说明.可视化和编制文档的一种标准语言,是非专利的第三代建模 ...

  10. K8s nginx-ingress 如何配置二级目录转发远程静态服务器基于Vue路由history模式打包的应用程序

    背景 首先这标题有点绕,我先解释下: 首先我们有静态服务器,上面某个目录有Vue路由history模式打包的应用程序(也就是build后的产物): 但是静态服务器一般不做对外域名用的,我们需要在k8s ...