索引

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. 万答#18,MySQL8.0 如何快速回收膨胀的UNDO表空间

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 背 ...

  2. 图片系列(6)不同版本上 Bitmap 内存分配与回收原理对比

    请点赞关注,你的支持对我意义重大. Hi,我是小彭.本文已收录到 GitHub · AndroidFamily 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] ...

  3. 如何使用.NET 6的IHostedService和BackgroundService?

    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 本章是<定制ASP NET 6.0框架系列文章>的第七篇.本文内容和定 ...

  4. 以太坊 layer2: optimism 源码学习(二) 提现原理

    作者:林冠宏 / 指尖下的幽灵.转载者,请: 务必标明出处. 掘金:https://juejin.im/user/1785262612681997 博客:http://www.cnblogs.com/ ...

  5. DataGridView控件绑定数据之后,置顶操作

    一个小小的置顶,就搞了半个小时,还是记录一下吧. 1.第一个问题就是datatable的插入只能是Insert DataRow,但是获取选中的行,都是DataGridViewRow,不能直接转换. 找 ...

  6. Linux之NFS服务搭建及autofs服务搭建

    NFS 网络文件系统,英文Network File System(NFS),是由SUN公司研制的UNIX表示层协议(presentation layer protocol),能使使用者访问网络上别处的 ...

  7. SpringMVC前置复习以及扩展

    SpringMVC ssm:mybatis+Spring+SpringMVC javaSE javaweb 框架 理解的DAO层和Service层 先简单来讲下Dao层,和Service层的概念: S ...

  8. 命令行配置Windows高级防火墙

    今天正好看到个帖子,询问如何通过命令行配置防火墙策略中远程IP的地址,特别是添加新的地址. 就是图中Scope里Remote IP address的地址. 第一反应就是用netsh firewall来 ...

  9. Grafana Loki 学习之踩坑记

    转发自:https://mp.weixin.qq.com/s/zfXNEkdDC9Vqd9lh1ptC1g Grafana 出品的 loki 日志框架完美地与 kubernetes 的 label 理 ...

  10. nginx反向代理Grafana

    官方文旦地址:https://grafana.com/tutorials/run-grafana-behind-a-proxy/ 一级路径 只需要修改nginx配置文件 # this is requi ...