索引

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. 技术分享 | 将GreatSQL添加到系统systemd服务

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

  2. Dubbo源码(七) - 集群

    前言 本文基于Dubbo2.6.x版本,中文注释版源码已上传github:xiaoguyu/dubbo 集群(cluster)就是一组计算机,它们作为一个总体向用户提供一组网络资源.这些单个的计算机系 ...

  3. Linux系列之链接

    前言 在类Unix系统中,一个文件有可能被多个名字引用.我们使用链接来实现这一点,链接共有两种类型:硬链接和软链接,本文分别来介绍它们. 硬链接 硬链接也允许指向文件,但与符号链接的方式不同.它们是U ...

  4. APT 安装 MySQL 提示错误:dpkg: error: dpkg frontend lock is locked by another process

    在安装 MySQL 的时候提示错误: ubuntu@VM-0-6-ubuntu:/opt$ sudo dpkg -i mysql-apt-config_0.8.22-1_all.deb dpkg: e ...

  5. ARC120D Bracket Score 2 (模拟)

    题面 给一个长度为 2 N 2N 2N 的序列 A A A,定义一个长度为 2 N 2N 2N 的合法括号序列的 得分(score) 为: 对于每对配对的括号 i , j i,j i,j, ∣ A i ...

  6. SpringCache的基本使用

    SpringCache SpringCache是一个框架,实现了基于注解的缓存功能.SpringCache提供了一层抽象,底层可以切换不同的cache实现.具体是通过CacheManager接口来统一 ...

  7. C 语言 struct 第一个成员变量的妙用

    一.双重身份 如下定义了一个 School 结构体: typedef struct School { int a; int b; }SCHOOL_S; SCHOOL_S stSch; 下面我们来输出一 ...

  8. LFS(Linux From Scratch)构建过程全记录(四):最后的准备

    写在前面 本章将进行一系列的环境配置 目录创建 在LFS中创建文件目录 我们可以用以下的指令来创建一些基础的目录,并进行连接 mkdir -pv $LFS/{etc,var} $LFS/usr/{bi ...

  9. Base64加密、解密

    #region Base64加密方法 /// <summary> /// Base64加密,采用utf8编码方式加密 /// </summary> /// <param ...

  10. 【疑难杂症】关于pytorch安装的一些问题

    问题一:选用哪个版本 直接下载Anaconda,会自动给你附加最合适的python版本,再去pytorch官网直接找到自己需要的版本下载 问题二:下载pytorch速度太慢 直接把下载代码最后面的-c ...