一文详解Go语言中的Option设计模式

关于什么是设计模式,笔者在这里就不做过多的解释。大家自行百度谷歌就好。下面我们聊聊Option设计模式,这个单词翻译过来就是选项的意思。

它一般都是用在初始化数据的时候使用。

type User struct {
    // 必须初始化的值
    Username string
    Age int

    // 非必要初始化的值
    Password string
}

结构体中,有些字段是必须要初始化的,而有些则是不用。那些不用初始化的字段就被称为可选项。用户根据自己的实际需求对其进行初始化。

一般来说,对于这种结构体,不论是必须初始化的字段还是非必须的,都是私有的字段,不会暴露给外界。

下面是一个标准的Option的设计模式

// 定义一个Option函数签名
type UserOption func(user *User)

// 提供一个可选函数
func WithUserPassword(password string) UserOption {
    return func(user *User) {
        user.Password = password
    }
}

type User struct {
    // 必须初始化的值
    Username string
    Age int

    // 非必要初始化的值
    Password string
}

// 定义一个初始化User的方法
func NewUser(username string, age int, opts...UserOption) *User {
    user := &User{
        Username: username,
        Age: age,
    }
    for _, opt := range opts {
        opt(user)
    }
    return user
}

步骤

  • 定义一个结构体,内部字段全部都是私有的,并且存在必须初始化字段和非必要初始化字段
  • 定义一个Option函数签名,参数是结构体指针,必须是结构体指针,因为只有指针才能设置上值
  • 定义一个初始化结构体的方法,参数是结构体必须要初始化的字段值,外加一个Option函数切片,返回值可以是结构体,也可以是指针结构体
  • 初始化结构体方法内部先初始化好一个最基本的结构体,然后遍历Option函数切片
  • 定义的Option函数实现最好用With开头,规范,不遵守也可以

Option模式变种

// 定义一个Option函数签名
type UserOptionErr func(user *User) error

// 提供一个可选函数
func WithUserPassword(password string) UserOption {
    return func(user *User) error {
        if password == "" {
            return errors.New("password 不能为空")
        }
        user.Password = password
        return nil
    }
}

type User struct {
    // 必须初始化的值
    Username string
    Age int

    // 非必要初始化的值
    Password string
}

// 定义一个初始化User的方法
func NewUser(username string, age int, opts...UserOption) (*User, error) {
    user := &User{
        Username: username,
        Age: age,
    }
    for _, opt := range opts {
        if err := opt(user); err != nil {
            return nil, err
        }
    }
    return user, nil
}

大家应该发现了,就是修改Option函数签名的返回值,这种模式可以用作对Option函数的参数进行校验。由于这里发生了变更,导致初始化结构体的方法也需要做出相应的变化。

对于Option模式,在很多场景中都能用到,并且也是非常好用的。大家记住它是在初始化数据的时候用就行,代码模式相对固定。

到此这篇关于一文详解Go语言中的Option设计模式的文章就介绍到这了,更多相关Go Option设计模式内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解Golang函数式选项(Functional Options)模式

    概览 最近阅读源码的时候看到一段不错的代码,但是当时却不是非常理解为什么这么写. 我们先来看一下源代码: type User struct { ID string Name string Age int Email string Phone string Gender string } type Option func(*User) func WithAge(age int) Option { return func(u *User) { u.Age = age } } func WithEma

  • Go|使用Options模式和建造者模式创建对象实战

    目录 复杂对象的问题 Options 模式 建造者模式 总结 复杂对象的问题 在 Golang 中一般创建复杂对象,一般会使用2种方式创建对象:Options 模式(函数式选项模式)和建造者模式.这两种模式都有其它们各自优点和缺点,如何使用主要还是要依赖于你的使用场景吧. 创建一个简单的对象 User. type User struct { Name string Age int } func NewObj(a string, b int) *User { user := User{} user

  • GO 函数式选项模式(Functional Options Pattern)

    Golang 开发者遇到的许多问题之一是尝试将一个函数的参数设置为可选. 这是一个非常常见的用例, 有些对象应该使用一些基本的默认设置来开箱即用, 并且你偶尔可能需要提供一些更详细的配置. 在很多语言中这很容易; 在 C 族语言中, 可以使用不同数量的参数提供相同函数的多个版本; 在像 PHP 这样的语言中, 可以给参数一个默认值,并在调用方法时忽略它们. 但是在 Golang 中, 这两种方式你哪个也用不了. 那么你如何创建一个函数, 用户可以指定一些额外的配置? 有很多可能的方法可以做到这一

  • 详解Go语言中for range的"坑"

    前言 Go 中的for range组合可以和方便的实现对一个数组或切片进行遍历,但是在某些情况下使用for range时很可能就会被"坑",下面用一段代码来模拟下: func main() { arr1 := []int{1, 2, 3} arr2 := make([]*int, len(arr1)) for i, v := range arr1 { arr2[i] = &v } for _, v := range arr2 { fmt.Println(*v) } } 代码解析

  • 详解C语言中return返回函数局部变量的问题

    目录 return返回栈区局部变量的指针 return返回栈区局部的临时变量 return只读数据段和static数据 在计算机中,释放空间并不需要将空间中的内容全部置成0或者1,而是只要设置这一块空间的数据无效即可.比如在下载文件时需要花很长时间,但是删除文件却只要几秒钟,这是因为操作系统只是把文件标识(文件头链接)删掉了,文件原文还保留着,我们没了文件标识就找不到这个文件了.所以删除后的文件,还可以用特殊的办法被找回来. 这也就意味着,当函数结束调用的时候,函数中的局部变量实际上还是在的,只

  • 详解C语言中return与exit的区别

    详解C语言中return与exit的区别 1,exit用于在程序运行的过程中随时结束程序,exit的参数是返回给OS的.main函数结束时也会隐式地调用exit函数.exit函数运行时首先会执行由atexit()函数登记的函数,然后会做一些自身的清理工作,同时刷新所有输出流.关闭所有打开的流并且关闭通过标准I/O函数tmpfile()创建的临时文件.exit是结束一个进程,它将删除进程使用的内存空间,同时把错误信息返回父进程,而return是返回函数值并退出函数 2,return是语言级别的,它

  • 详解 Go 语言中 Map 类型和 Slice 类型的传递

    Map 类型 先看例子 m1: func main() { m := make(map[int]int) mdMap(m) fmt.Println(m) } func mdMap(m map[int]int) { m[1] = 100 m[2] = 200 } 结果是 map[2:200 1:100] 我们再修改如下 m2: func main() { var m map[int]int mdMap(m) fmt.Println(m) } func mdMap(m map[int]int) {

  • 详解C语言中Char型指针数组与字符数组的区别

    详解C语言中Char型指针数组与字符数组的区别 1.char 类型的指针数组:每个元素都指向一个字符串,指向可以改变 char *name[3] = { "abc", "def", "gbk" }; for(int i = 0 ; i < strlen(name); i ++){ printf("%s\n", *(name+i)); //printf("%s\n", name[i]); } //指向改

  • 详解Golang语言中的interface

    interface是一组method签名的组合,interface可以被任意对象实现,一个对象也可以实现多个interface.任意类型都实现了空interface(也就是包含0个method的interface),空interface可以存储任意类型的值.interface定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了此接口. go version go1.12 package main import ( "fmt" ) // 定义struct type Hu

  • 详解go语言中type关键词的几种使用

    type是go语法里的重要而且常用的关键字,type绝不只是对应于C/C++中的typedef.搞清楚type的使用,就容易理解go语言中的核心概念struct.interface.函数等的使用.以下我用例子代码总结描述,请特别留意代码中的注释. 1.定义结构体 //结构体定义 type person struct { name string //注意后面不能有逗号 age int } func main() { //结构体初始化 p := person{ name: "taozs",

  • 详解R语言中的PCA分析与可视化

    1. 常用术语 (1)标准化(Scale) 如果不对数据进行scale处理,本身数值大的基因对主成分的贡献会大.如果关注的是变量的相对大小对样品分类的贡献,则应SCALE,以防数值高的变量导入的大方差引入的偏见.但是定标(scale)可能会有一些负面效果,因为定标后变量之间的权重就是变得相同.如果我们的变量中有噪音的话,我们就在无形中把噪音和信息的权重变得相同,但PCA本身无法区分信号和噪音.在这样的情形下,我们就不必做定标. (2)特征值 (eigen value) 特征值与特征向量均为矩阵分

  • 详解C++语言中std::array的神奇用法

    概述 std::array是在C++11标准中增加的STL容器,它的设计目的是提供与原生数组类似的功能与性能.也正因此,使得std::array有很多与其他容器不同的特殊之处,比如:std::array的元素是直接存放在实例内部,而不是在堆上分配空间:std::array的大小必须在编译期确定:std::array的构造函数.析构函数和赋值操作符都是编译器隐式声明的--这让很多用惯了std::vector这类容器的程序员不习惯,觉得std::array不好用.但实际上,std::array的威力

  • 详解go语言中sort如何排序

    目录 sort包源码解读 前言 如何使用 基本数据类型切片的排序 自定义Less排序比较器 自定义数据结构的排序 分析下源码 不稳定排序 稳定排序 查找 Interface 总结 参考 sort 包源码解读 前言 我们的代码业务中很多地方需要我们自己进行排序操作,go 标准库中是提供了 sort 包是实现排序功能的,这里来看下生产级别的排序功能是如何实现的. go version go1.16.13 darwin/amd64 如何使用 先来看下 sort 提供的主要功能 对基本数据类型切片的排序

随机推荐