乐趣区

关于golang:Go-函数式编程Higherorder-function

在申请处理过程中,应用程序会承受和解决申请,而后返回响应后果。在该过程中,还存在一些通用的性能,例如:鉴权、监控、链路追踪。泛滥 RPC 框架会提供称之为 Middleware 或者 Interceptor 等概念,以可插拔的形式来反对上述谈到的泛滥性能。以 gRPC 为例,工作原理如图:

其服务端的接口如下所示:

func UnaryServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error)

func StreamServerInterceptor (srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error

能够看到,接口明确定义了输出参数,输入后果。如果咱们要本人实现一个组件,须要反对使用者传入特定的配置,有没有什么方法能够做到呢?

答案是必定的。

Higher-order function

在理解具体的解决方案之前,须要先理解一个概念叫Higher-order function(高阶函数)

高阶函数是指至多反对以下特定之一的函数:

  1. 将一个或多个函数作为参数(即过程参数),
  2. 返回函数作为其后果

第二点,正是须要的个性。以限流的 interceptor 为例,反对传入自定义的限流器。此时就须要定义一个以限流器为参数的高阶函数,而后返回的函数是框架须要的 Interceptor,并在 Interceptor 函数内应用传入的限流器判断是否须要限流。依照接口限流的 Interceptor 具体实现为:

type Limiter interface {Limit(key string) bool
}

func UnaryServerInterceptor(limiter Limiter) grpc.UnaryServerInterceptor {return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {if limiter.Limit(info.FullMethod) {return nil, status.Errorf(codes.ResourceExhausted, "%s is rejected by grpc_ratelimit middleware, please retry later.", info.FullMethod)
        }
        return handler(ctx, req)
    }
}

...

目前传入的参数是固定的,能够这么来实现。更进一步,如果应用比较复杂,除了以后曾经确定的参数,能够预期当前会减少更多的参数。也就要求以后设计的接口须要有很好的扩展性。还有方法么?

答案同样是必定的。

Functional Options

没有意外,利用的就是高阶函数的第一点,该编程模式有一个特定的名称:Functional Options。

首先为传入的参数定义构造体

type options struct {
    byMethod  bool
    byUser    bool
    byClientIP bool
}

其次,再定义一个函数类型:

type Option func(*Options)

再次,定义批改配置的一组函数

func ByMethod(m bool) Option {return func(o *options) {o.byMethod = m}
}

func ByUser(u bool) Option {return func(o *options) {o.byUser = u}
}

func ByClientIP(c bool) Option {return func(o *options) {o.byClientIP = c}
}

最初,批改提供的 Interceptor 为:

func UnaryServerInterceptor(limiter Limiter, opts ...Option) grpc.UnaryServerInterceptor {return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
        default := options {
            byMethod: true,
            byUser: false,
            byClientIP: false,
        }
        for _, opt := range opts {opt(&default)
        }
        ...
        return handler(ctx, req)
    }
}

如是,你就领有了一个具备扩展性、反对自定义参数的 Interceptor。

最初

做个总结,谈个观点:

  1. 高阶函数,并不是属于哪一个特定的编程语言。其余语言如 C ++,同样反对相似的个性。
  2. 作为架构师须要理解实现细节么,答案是须要。否则,在特定环境下,拿什么来撑持设计所谓的扩展性呢。

本文作者 :cyningsun
本文地址 :https://www.cyningsun.com/07-…
版权申明:本博客所有文章除特地申明外,均采纳 CC BY-NC-ND 3.0 CN 许可协定。转载请注明出处!

退出移动版