golang 实现修饰器

目录

修饰器模式非常有用在 python 中使用@这个语法糖来实现,在其他函数式语言中用高阶函数来实现也非常简单和自然,但是在 golang 这种静态语言中却有点麻烦
下面我写出了一个逐步完善的方案。

方案 1

这个是我在网上找的方案,非常简单但是缺陷非常明显。

package main

type decorator func()

func (this decorator) invoke() {
  println("before")
  this()
  println("after")
}


func myFunc() {
  println("blah")
}


func main() {
  x := decorator(myFunc)
  x.invoke()
}
// 缺陷:1.我们的 myFunc 函数必须是无参数的,也就是没法把"blah"改成其他的

方案 2

为了改善上面的缺陷我想到了利用闭包把有参函数包在一个无参函数内来解决这个问题,下面看一下实现

package main

type decorator func()

func (this decorator) invoke() {
  println("before")
  this()
  println("after")
}


func myFunc(s string) {
  println(s)
}

func call(s string) func() {
  f := func() {
    myFunc(s)
  }
  return f
}

func main() {
  f := call("hh")
  x := decorator(f)
  x.invoke()
}

//这时我们就可以给我们 myFunc 传入参数了,但是这个修饰器依然非常不完美,因为我们在 call 中写死了 myFunc,如果有个 myFunc1 那么我们必须再写一个
//call1 函数,这样非常麻烦,能不能我们可以给 call 传入任意类型的函数呢,可以利用 golang 的 reflect 来实现

方案 3

这个方案进一步解决了方案 2 中存在的问题

package main

import (
  "reflect"
)

type decorator func()

func (this decorator) invoke() {
  println("before")
  this()
  println("after")
}

func myFunc(s string) {
  println(s)
}

func call(func_name interface{}, params ...interface{}) func() {
  f := func() {
    var fc = reflect.ValueOf(func_name)
    in := make([]reflect.Value, len(params))
    for k, param := range params {
      in[k] = reflect.ValueOf(param)
    }
    fc.Call(in)
  }
  return f
}

func main() {
  f := call(myFunc, "hh")
  x := decorator(f)
  x.invoke()
}

// 这样这个修饰器就比较完善了,但是还是有个问题,我们如何实现多重修饰,其实这个代码已经可以实现了

多重修饰

package main

import (
  "reflect"
)

type decorator func()
type decorator1 func()

func (this decorator) invoke() {
  println("before")
  this()
  println("after")
}

func (this decorator1) invoke() {
  println("before1")
  this()
  println("after1")
}


func myFunc(s string) {
  println(s)
}

func call(func_name interface{}, params ...interface{}) func() {
  f := func() {
    var fc = reflect.ValueOf(func_name)
    in := make([]reflect.Value, len(params))
    for k, param := range params {
      in[k] = reflect.ValueOf(param)
    }
    fc.Call(in)
  }
  return f
}

func main() {
  f := call(myFunc, "bb")
  x := decorator1(decorator(f).invoke)
  x.invoke()
}

目录