doulu8415 2018-06-15 20:54
浏览 14
已采纳

在每个功能之前自动运行代码

I would like to run some code (authorization check) at the start of many functions, such as:

func (s *apiService) get(request Request) (Result, error) {
  err := authorizationCheck(request)
  if err != nil {
    return nil, err
  }
  //method logic
}

func (s *apiService) put(request Request) (Result, error) {
  err := authorizationCheck(request)
  if err != nil {
    return nil, err
  }
  //method logic
}

Is there an elegant way to avoid doing the same authorization check at the start of every function?

  • 写回答

1条回答 默认 最新

  • douyi0219 2018-06-15 21:13
    关注

    With a simple wrapper

    Since all the methods (at least I assume so) have the same signature, you can put all the redundant code inside a wrapper function which takes the function you need to run as an additional argument. The wrapper will first check for the error and then run the function. As a result, your methods will only need to have relevant code inside, without bothering to check for the error first.

    Here's an example, I called the wrapper wrap just to make it clear:

    func (s *apiService) get(request Request) (Result, error) {
        //method logic
    }
    
    func (s *apiService) put(request Request) (Result, error) {
        //method logic
    }
    
    func wrap(f func (Request) (Result, error), request Request) (Result, error) {
        err := authorizationCheck(request)
        if err != nil {
            return nil, err
        }
    
        return f(request)
    }
    

    Then, later in your code:

    res, err := wrap(s.get, someRequest)
    

    With a decorator

    Very similar to the above, but cleaner: instead of creating a wrapper you can implement a decorator which returns a function which wraps your methods and does the error checking before calling them. This again can only be done if all the methods have the same signature, but it is more powerful and IMHO a cleaner solution than using a wrapper.

    Here's an example, the decorator is decorate (yay to my originality):

    func (s *apiService) get(request Request) (Result, error) {
        //method logic
    }
    
    func (s *apiService) put(request Request) (Result, error) {
        //method logic
    }
    
    func decorate(f func(Request) (Result, error)) func(Request) (Result, error) {
        return func(r Request) (Result, error) {
            err := authorizationCheck(r)
            if err != nil {
                return nil, err
            }
    
            return f(r)
        }
    }
    

    Then, later in your code:

    res, err := decorate(s.get)(someRequest)
    

    Methods or plain functions?

    Whether you prefer a simple wrapper or a decorator, you can also make them methods of your apiService object if you want (just by adding (s *apiService) before their name), there really is no big difference, but this would be the preferred option if you want your struct to have the wrapper/decorator available wherever you use it and not just in that particular file.

    The relative calls would then become:

    res, err := s.wrap(s.get, someRequest)
    

    and:

    res, err := s.decorate(s.get)(someRequest)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 wpf datagrid如何实现多层表头
  • ¥15 为啥画版图在Run DRC会出现Connect Error?可我Calibre的hostname和计算机的hostname已经设置成一样的了。
  • ¥20 网站后台使用极速模式非常的卡
  • ¥20 Keil uVision5创建project没反应
  • ¥15 mmseqs内存报错
  • ¥15 vika文档如何与obsidian同步
  • ¥15 华为手机相册里面的照片能够替换成自己想要的照片吗?
  • ¥15 陆空双模式无人机飞控设置
  • ¥15 sentaurus lithography
  • ¥100 求抖音ck号 或者提ck教程