12

Go语言函数式选项模式

 3 years ago
source link: http://www.lzhpo.com/article/136
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

普通的结构体模式存在的缺点

普通模式需要输入相应的参数,但是有的时候我们有默认参数的,所以普通模式不灵活。

// student结构体type StudentModel struct {    name   string    school string    age    int}// 构建结构体,必须输入对应参数func NewStudentModel(name, school string, age int) *StudentModel {    return &StudentModel{        name:   name,        school: school,        age:    age,    }}func NewStudentModel2(school string, age int) *StudentModel {    return &StudentModel{        // 这样子未免太蹩脚了        name:   "会打篮球的程序猿",        school: school,        age:    age,    }}// 构建结构体,这种方式不能修改默认属性,不够灵活func NewStudentDefault() *Student {    return &Student{        name:   "lzhpo",        school: "北京大学",        age:    20,    }}

函数式选项模式运用到的知识点?

闭包(闭包 = 匿名函数 + 引用环境):一个持有外部环境变量的函数就是闭包。

函数式选项模式的优点?

可以根据需要,灵活的设置结构体的值。

Go语言函数式选项模式-示例Demo

basketball.go

package structs// 定义一个篮球结构体type BasketBall struct {    Name string    Color string    Price float64}// 针对篮球结构体定义一个函数类型type BasketBallFunc func(*BasketBall)func WithName(name string) BasketBallFunc {    return func(basketBall *BasketBall) {        basketBall.Name = name    }}func WithColor(color string) BasketBallFunc {    return func(basketBall *BasketBall) {        basketBall.Color = color    }}func WithPrice(price float64) BasketBallFunc {    return func(basketBall *BasketBall) {        basketBall.Price = price    }}// 结构体默认实例var (    basketBallDefault = BasketBall{        Name: "斯伯丁比赛专用球",        Color: "黄色",        Price: 300.99,    })// 创建一个构造函数,传入的是我定义的函数类型func NewBasketBall(opts ...BasketBallFunc) *BasketBall {    // 默认值,这里也可以抽一个默认值的实例,直接引用也可以    //temp := BasketBall{    //    name: "斯伯丁比赛专用球",    //    color: "黄色",    //    price: 300.99,    //}    temp := basketBallDefault    // 遍历,并对每一项应用返回的闭包到结构体的选项变量    for _, opt := range opts {        opt(&temp)    }    return &temp}

main.go

package mainimport (    "fmt"    "study-golang/function-model/model-demo3/structs")/*Go语言函数式选项模式:为什么要使用函数式选项模式?- 普通模式需要输入相应的参数,但是有的时候我们有默认参数的,所以普通模式不灵活。函数式选项模式运用到的知识点?- 闭包(闭包 = 匿名函数 + 引用环境):一个持有外部环境变量的函数就是闭包。函数式选项模式的优点?- 可以根据需要,灵活的设置结构体的值。函数式选项模式设计参考来源,go-micro源码:https://github.com/micro/go-micro/blob/master/options.go */func main() {    fmt.Println(structs.NewBasketBall())    fmt.Println(structs.NewBasketBall(structs.WithName("李宁比赛专用球")))    fmt.Println(structs.NewBasketBall(        structs.WithName("李宁比赛专用球"), structs.WithColor("白色")))    fmt.Println(structs.NewBasketBall(        structs.WithName("李宁比赛专用球"), structs.WithColor("白色"), structs.WithPrice(129.99)))}

运行结果:

&{斯伯丁比赛专用球 黄色 300.99}&{李宁比赛专用球 黄色 300.99}&{李宁比赛专用球 白色 300.99}&{李宁比赛专用球 白色 129.99}

函数式选项模式应用-go-micro源码

https://github.com/micro/go-micro/blob/master/options.go

里面就用到了函数式选项模式

options.go源代码解析:

go-micro里面的options的函数式选择模式.png

package microimport (    "context"    "go-micro/go-micro-master/config/source/cli"    "time"    "github.com/micro/cli/v2"    "github.com/micro/go-micro/v2/auth"    "github.com/micro/go-micro/v2/broker"    "github.com/micro/go-micro/v2/client"    "github.com/micro/go-micro/v2/config"    "github.com/micro/go-micro/v2/config/cmd"    "github.com/micro/go-micro/v2/debug/profile"    "github.com/micro/go-micro/v2/debug/trace"    "github.com/micro/go-micro/v2/registry"    "github.com/micro/go-micro/v2/router"    "github.com/micro/go-micro/v2/runtime"    "github.com/micro/go-micro/v2/selector"    "github.com/micro/go-micro/v2/server"    "github.com/micro/go-micro/v2/store"    "github.com/micro/go-micro/v2/transport")/*【函数式选项设计模式】 */// 服务注册结构体// Options for micro servicetype Options struct {    Auth      auth.Auth    Broker    broker.Broker    Cmd       cmd.Cmd    Config    config.Config    Client    client.Client    Server    server.Server    Store     store.Store    Registry  registry.Registry    Router    router.Router    Runtime   runtime.Runtime    Transport transport.Transport    Profile   profile.Profile    // Before and After funcs    BeforeStart []func() error    BeforeStop  []func() error    AfterStart  []func() error    AfterStop   []func() error    // Other options for implementations of the interface    // can be stored in a context    Context context.Context    Signal bool}// 创建newOptions构造函数,传入的是定义的函数类型 type Option func(*Options)  在micro.go里面func newOptions(opts ...Option) Options {    // 默认结构体属性值    opt := Options{        Auth:      auth.DefaultAuth,        Broker:    broker.DefaultBroker,        Cmd:       cmd.DefaultCmd,        Config:    config.DefaultConfig,        Client:    client.DefaultClient,        Server:    server.DefaultServer,        Store:     store.DefaultStore,        Registry:  registry.DefaultRegistry,        Router:    router.DefaultRouter,        Runtime:   runtime.DefaultRuntime,        Transport: transport.DefaultTransport,        Context:   context.Background(),        Signal:    true,    }    // 遍历,并对每一项应用返回的闭包到结构体的选项变量    for _, o := range opts {        o(&opt)    }    return opt}// 设置Broker// Broker to be used for servicefunc Broker(b broker.Broker) Option {    // 闭包,进入的是一个外部变量,返回的是一个匿名函数    return func(o *Options) {        o.Broker = b        // Update Client and Server        o.Client.Init(client.Broker(b))        o.Server.Init(server.Broker(b))    }}// 。。。。下面都是一样的道理// 设置Cmdfunc Cmd(c cmd.Cmd) Option {    return func(o *Options) {        o.Cmd = c    }}// 设置Client。。。。。下面一大堆也是一样的道理// Client to be used for servicefunc Client(c client.Client) Option {    return func(o *Options) {        o.Client = c    }}// Context specifies a context for the service.// Can be used to signal shutdown of the service and for extra option values.func Context(ctx context.Context) Option {    return func(o *Options) {        o.Context = ctx    }}// HandleSignal toggles automatic installation of the signal handler that// traps TERM, INT, and QUIT.  Users of this feature to disable the signal// handler, should control liveness of the service through the context.func HandleSignal(b bool) Option {    return func(o *Options) {        o.Signal = b    }}// Profile to be used for debug profilefunc Profile(p profile.Profile) Option {    return func(o *Options) {        o.Profile = p    }}// Server to be used for servicefunc Server(s server.Server) Option {    return func(o *Options) {        o.Server = s    }}// Store sets the store to usefunc Store(s store.Store) Option {    return func(o *Options) {        o.Store = s    }}// Registry sets the registry for the service// and the underlying componentsfunc Registry(r registry.Registry) Option {    return func(o *Options) {        o.Registry = r        // Update router        o.Router.Init(router.Registry(r))        // Update server        o.Server.Init(server.Registry(r))        // Update Broker        o.Broker.Init(broker.Registry(r))    }}// Tracer sets the tracer for the servicefunc Tracer(t trace.Tracer) Option {    return func(o *Options) {        o.Server.Init(server.Tracer(t))    }}// Auth sets the auth for the servicefunc Auth(a auth.Auth) Option {    return func(o *Options) {        o.Auth = a        o.Server.Init(server.Auth(a))    }}// Config sets the config for the servicefunc Config(c config.Config) Option {    return func(o *Options) {        o.Config = c    }}// Selector sets the selector for the service clientfunc Selector(s selector.Selector) Option {    return func(o *Options) {        o.Client.Init(client.Selector(s))    }}// Transport sets the transport for the service// and the underlying componentsfunc Transport(t transport.Transport) Option {    return func(o *Options) {        o.Transport = t        // Update Client and Server        o.Client.Init(client.Transport(t))        o.Server.Init(server.Transport(t))    }}// Runtime sets the runtimefunc Runtime(r runtime.Runtime) Option {    return func(o *Options) {        o.Runtime = r    }}// Router sets the routerfunc Router(r router.Router) Option {    return func(o *Options) {        o.Router = r        // Update client        o.Client.Init(client.Router(r))    }}// Convenience options// Address sets the address of the serverfunc Address(addr string) Option {    return func(o *Options) {        o.Server.Init(server.Address(addr))    }}// Name of the servicefunc Name(n string) Option {    return func(o *Options) {        o.Server.Init(server.Name(n))    }}// Version of the servicefunc Version(v string) Option {    return func(o *Options) {        o.Server.Init(server.Version(v))    }}// Metadata associated with the servicefunc Metadata(md map[string]string) Option {    return func(o *Options) {        o.Server.Init(server.Metadata(md))    }}// Flags that can be passed to servicefunc Flags(flags ...cli.Flag) Option {    return func(o *Options) {        o.Cmd.App().Flags = append(o.Cmd.App().Flags, flags...)    }}// Action can be used to parse user provided cli optionsfunc Action(a func(*cli.Context) error) Option {    return func(o *Options) {        o.Cmd.App().Action = a    }}// RegisterTTL specifies the TTL to use when registering the servicefunc RegisterTTL(t time.Duration) Option {    return func(o *Options) {        o.Server.Init(server.RegisterTTL(t))    }}// RegisterInterval specifies the interval on which to re-registerfunc RegisterInterval(t time.Duration) Option {    return func(o *Options) {        o.Server.Init(server.RegisterInterval(t))    }}// WrapClient is a convenience method for wrapping a Client with// some middleware component. A list of wrappers can be provided.// Wrappers are applied in reverse order so the last is executed first.func WrapClient(w ...client.Wrapper) Option {    return func(o *Options) {        // apply in reverse        for i := len(w); i > 0; i-- {            o.Client = w[i-1](o.Client)        }    }}// WrapCall is a convenience method for wrapping a Client CallFuncfunc WrapCall(w ...client.CallWrapper) Option {    return func(o *Options) {        o.Client.Init(client.WrapCall(w...))    }}// WrapHandler adds a handler Wrapper to a list of options passed into the serverfunc WrapHandler(w ...server.HandlerWrapper) Option {    return func(o *Options) {        var wrappers []server.Option        for _, wrap := range w {            wrappers = append(wrappers, server.WrapHandler(wrap))        }        // Init once        o.Server.Init(wrappers...)    }}// WrapSubscriber adds a subscriber Wrapper to a list of options passed into the serverfunc WrapSubscriber(w ...server.SubscriberWrapper) Option {    return func(o *Options) {        var wrappers []server.Option        for _, wrap := range w {            wrappers = append(wrappers, server.WrapSubscriber(wrap))        }        // Init once        o.Server.Init(wrappers...)    }}// Before and Afters// BeforeStart run funcs before service startsfunc BeforeStart(fn func() error) Option {    return func(o *Options) {        o.BeforeStart = append(o.BeforeStart, fn)    }}// BeforeStop run funcs before service stopsfunc BeforeStop(fn func() error) Option {    return func(o *Options) {        o.BeforeStop = append(o.BeforeStop, fn)    }}// AfterStart run funcs after service startsfunc AfterStart(fn func() error) Option {    return func(o *Options) {        o.AfterStart = append(o.AfterStart, fn)    }}// AfterStop run funcs after service stopsfunc AfterStop(fn func() error) Option {    return func(o *Options) {        o.AfterStop = append(o.AfterStop, fn)    }}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK