您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > Go语言

Go 函数装饰器模式教程

时间:2022-01-11 10:14:49  来源:  作者:杨同学编程

装饰器在 Python 和 TypeScript 等其他编程语言中肯定更为突出,但这并不是说你不能在 Go 中使用它们。事实上,对于某些问题,使用装饰器是我们希望在本教程中找到的完美解决方案。

了解装饰器模式

装饰器本质上允许您包装现有功能并在顶部附加或添加您自己的自定义功能。

在 Go 中,函数被视为第一类对象,这本质上意味着您可以像传递变量一样传递它们。让我们用一个非常简单的例子来看看这个:

package main

import (
  "fmt"
  "time"
)

func myFunc() {
  fmt.Println("Hello World")
  time.Sleep(1 * time.Second)
}

func main() {
  fmt.Printf("Type: %Tn", myFunc)
}

所以,在这个例子中,我们定义了一个名为 的函数myFunc,它简单地打印出Hello World。然而,在我们的main()函数体中,我们已经调用fmt.Printf并且我们习惯于%T打印出我们作为第二个参数传入的值的类型。在这种情况下,我们正在传递myFunc,随后将打印出以下内容:

$ go run test.go
Type: func()

那么,这对我们 Go 开发人员意味着什么?好吧,它强调了函数可以在我们代码库的其他部分中传递并用作参数的事实。

让我们通过进一步扩展我们的代码库并添加一个coolFunc()将函数作为其唯一参数的函数来看看这一点:

package main

import (
  "fmt"
  "time"
)

func myFunc() {
  fmt.Println("Hello World")
  time.Sleep(1 * time.Second)
}

// coolFunc takes in a function
// as a parameter
func coolFunc(a func()) {
    // it then immediately calls that functino
  a()
}

func main() {
  fmt.Printf("Type: %Tn", myFunc)
  // here we call our coolFunc function
  // passing in myFunc
    coolFunc(myFunc)
}

当我们尝试运行它时,我们应该看到我们的新输出具有我们 Hello World期望的字符串:

$ go run test.go
Type: func()
Hello World

现在,这可能会让您感到有些奇怪。你为什么想做这样的事情?它本质上为您的调用增加了一层抽象,myFunc并使代码复杂化,而没有真正增加太多价值。

一个简单的装饰器

让我们看看如何使用这种模式为我们的代码库添加一些价值。如果需要,我们可以在执行特定函数时添加一些额外的日志记录,以突出显示它的开始和结束时间。

package main

import (
    "fmt"
    "time"
)

func myFunc() {
  fmt.Println("Hello World")
    time.Sleep(1 * time.Second)
}

func coolFunc(a func()) {
    fmt.Printf("Starting function execution: %sn", time.Now())
    a()
    fmt.Printf("End of function execution: %sn", time.Now())
}

func main() {
    fmt.Printf("Type: %Tn", myFunc)
    coolFunc(myFunc)
}

调用此命令后,您应该会看到如下所示的日志:

$ go run test.go
Type: func()
Starting function execution: 2018-10-21 11:11:25.011873 +0100 BST m=+0.000443306
Hello World
End of function execution: 2018-10-21 11:11:26.015176 +0100 BST m=+1.003743698

如您所见,我们已经能够有效地包装我的原始函数,而无需更改它的实现。我们现在能够清楚地看到该函数何时启动以及何时完成执行,并且它向我们强调了该函数只需大约一秒钟即可完成执行。

现实世界的例子

让我们再看几个例子,看看我们如何使用装饰器来获得更多的名声和财富。我们将使用一个非常简单的 http Web 服务器并装饰我们的端点,以便我们可以验证传入请求是否具有特定的标头集。

如果您想了解更多关于在 Go 中编写简单 REST API 的信息,那么我建议您在此处查看我的另一篇文章: 在 Go 中创建 REST API

package main

import (
    "fmt"
    "log"
    "net/http"
)

func homePage(w http.ResponseWriter, r *http.Request) {
    fmt.Println("Endpoint Hit: homePage")
    fmt.Fprintf(w, "Welcome to the HomePage!")
}

func handleRequests() {
    http.HandleFunc("/", homePage)
    log.Fatal(http.ListenAndServe(":8081", nil))
}

func main() {
    handleRequests()
}

如您所见,我们的代码中没有什么特别复杂的。我们设置了一个net/http 路由器,服务于单个/端点。

让我们添加一个非常简单的身份验证装饰器函数,它将检查请求Authorized头是否设置为true传入请求。

package main

import (
    "fmt"
    "log"
    "net/http"
)

func isAuthorized(endpoint func(http.ResponseWriter, *http.Request)) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

        fmt.Println("Checking to see if Authorized header set...")

        if val, ok := r.Header["Authorized"]; ok {
            fmt.Println(val)
            if val[0] == "true" {
                fmt.Println("Header is set! We can serve content!")
                endpoint(w, r)
            }
        } else {
            fmt.Println("Not Authorized!!")
            fmt.Fprintf(w, "Not Authorized!!")
        }
    })
}

func homePage(w http.ResponseWriter, r *http.Request) {
    fmt.Println("Endpoint Hit: homePage")
    fmt.Fprintf(w, "Welcome to the HomePage!")
}

func handleRequests() {

    http.Handle("/", isAuthorized(homePage))
    log.Fatal(http.ListenAndServe(":8081", nil))
}

func main() {
    handleRequests()
}

注意:这绝对不是保护 REST API 的正确方法,我建议您考虑使用 JWT 或 OAuth2 来实现该目标!

所以,让我们分解一下并尝试了解发生了什么!

我们创建了一个名为的新装饰器函数isAuthorized(),它接收一个与原始homePage函数具有相同签名的函数。然后返回一个http.Handler.

在我们的isAuthorized()函数体中,我们返回一个 new http.HandlerFunc来验证我们的Authorized header的工作是 set 和 equals true。现在,这是一个大大简化的版本OAuth2身份验证/授权,有一些细微的差异,但它让您大致了解它是如何工作的。

然而,要注意关键是我们已经设法装饰现有端点并在所述端点周围添加某种形式的身份验证,而无需更改该功能的现有实现。

现在,如果我们要添加一个我们想要保护的新端点,我们可以轻松地这样做:

// define our newEndpoint function. Notice how, yet again,
// we don't do any authentication based stuff in the body
// of this function
func newEndpoint(w http.ResponseWriter, r *http.Request) {
    fmt.Println("My New Endpoint")
    fmt.Fprintf(w, "My second endpoint")
}

func handleRequests() {

    http.Handle("/", isAuthorized(homePage))
  // register our /new endpoint and decorate our
  // function with our isAuthorized Decorator
  http.Handle("/new", isAuthorized(newEndpoint))
    log.Fatal(http.ListenAndServe(":8081", nil))
}

这突出了装饰器模式的主要优点,在我们的代码库中包装代码非常简单。我们可以使用相同的方法轻松添加新的经过身份验证的端点

结论

希望本教程有助于揭开装饰器的神秘面纱,以及如何在自己的基于 Go 的程序中使用装饰器模式。我们了解了装饰器模式的好处以及如何使用它来用新功能包装现有功能。

在本教程的第二部分,我们查看了一个更现实的示例,说明如何在自己的生产级 Go 系统中使用它。

如果您喜欢本教程,请随时广泛分享这篇文章,它确实对网站有帮助,我将不胜感激!如果您有任何问题和/或意见,请在下面的评论部分告诉我!



Tags:Go   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
装饰器在 Python 和 TypeScript 等其他编程语言中肯定更为突出,但这并不是说你不能在 Go 中使用它们。事实上,对于某些问题,使用装饰器是我们希望在本教程中找到的完美解决方案...【详细内容】
2022-01-11  Tags: Go  点击:(0)  评论:(0)  加入收藏
Hello,大家好,又见面了!上一遍我们将 channel 相关基础以及使用场景。这一篇,还需要再次进阶理解channel 阻塞问题。以下创建一个chan类型为int,cap 为3。ch := make(chan string...【详细内容】
2022-01-04  Tags: Go  点击:(11)  评论:(0)  加入收藏
数据是时代发展与科技进步的产物,也是当下时代最重要的生产要素之一。要让数据进入市场实现经济效益,需要明确界定所有、支配、使用、收益、处置等产权权能的完整技术和规则要...【详细内容】
2021-12-31  Tags: Go  点击:(5)  评论:(0)  加入收藏
Go 泛型定了,有哪些好的使用场景,哪些不好的应用场景,亦或哪些使用看起来丑?本文聊聊这个问题。01 简介泛型很棒,而且 Go 变得比以前更方便了。但是与可能非常有用的 channel 类...【详细内容】
2021-12-29  Tags: Go  点击:(14)  评论:(0)  加入收藏
以隐私为主打的搜索引擎 DuckDuckGo,在 2021 年继续保持着快速的增长 —— 日均检索次数超 1 亿,较去年同期高出近 47% 。与其它搜索服务提供商相比,DuckDuckGo 宣称...【详细内容】
2021-12-29  Tags: Go  点击:(13)  评论:(0)  加入收藏
一. 配置yum源在目录 /etc/yum.repos.d/ 下新建文件 google-chrome.repovim /etc/yum.repos.d/google-chrome.repo按i进入编辑模式写入如下内容:[google-chrome]name=googl...【详细内容】
2021-12-23  Tags: Go  点击:(15)  评论:(0)  加入收藏
昨日谷歌宣布,自2022年12月19日开始停止对OnHub的软件支持,OnHub路由器仍将提供Wi-Fi信号,但用户无法用谷歌Home应用程序管理它。无法更新Wi-Fi网络设置、添加额外的Wifi设备或...【详细内容】
2021-12-22  Tags: Go  点击:(11)  评论:(0)  加入收藏
zip 是一种常见的归档格式,本文讲解 Go 如何操作 zip。首先看看 zip 文件是如何工作的。以一个小文件为例:(类 Unix 系统下)$ cat hello.textHello!执行 zip 命令进行归档:$ zip...【详细内容】
2021-12-17  Tags: Go  点击:(20)  评论:(0)  加入收藏
流水线(Pipeline)是把一个重复的过程分解为若干个子过程,使每个子过程与其他子过程并行进行的技术。本文主要介绍了诞生于云原生时代的流水线框架 Argo。 什么是流水线?在计算机...【详细内容】
2021-11-30  Tags: Go  点击:(25)  评论:(0)  加入收藏
大家好,我是 polarisxu。前段时间,Russ Cox 明确了泛型相关的事情,原计划在标准库中加入泛型相关的包,改放到 golang.org/x/exp 下。目前,Go 泛型的主要设计者 ianlancetaylor 完...【详细内容】
2021-11-30  Tags: Go  点击:(30)  评论:(0)  加入收藏
▌简易百科推荐
装饰器在 Python 和 TypeScript 等其他编程语言中肯定更为突出,但这并不是说你不能在 Go 中使用它们。事实上,对于某些问题,使用装饰器是我们希望在本教程中找到的完美解决方案...【详细内容】
2022-01-11  杨同学编程    Tags:Go   点击:(0)  评论:(0)  加入收藏
Hello,大家好,又见面了!上一遍我们将 channel 相关基础以及使用场景。这一篇,还需要再次进阶理解channel 阻塞问题。以下创建一个chan类型为int,cap 为3。ch := make(chan string...【详细内容】
2022-01-04  metashops    Tags:Go 语言   点击:(11)  评论:(0)  加入收藏
Go 泛型定了,有哪些好的使用场景,哪些不好的应用场景,亦或哪些使用看起来丑?本文聊聊这个问题。01 简介泛型很棒,而且 Go 变得比以前更方便了。但是与可能非常有用的 channel 类...【详细内容】
2021-12-29    Go语言中文网  Tags:泛型   点击:(14)  评论:(0)  加入收藏
zip 是一种常见的归档格式,本文讲解 Go 如何操作 zip。首先看看 zip 文件是如何工作的。以一个小文件为例:(类 Unix 系统下)$ cat hello.textHello!执行 zip 命令进行归档:$ zip...【详细内容】
2021-12-17  Go语言中文网    Tags:Go语言   点击:(20)  评论:(0)  加入收藏
大家好,我是 polarisxu。前段时间,Russ Cox 明确了泛型相关的事情,原计划在标准库中加入泛型相关的包,改放到 golang.org/x/exp 下。目前,Go 泛型的主要设计者 ianlancetaylor 完...【详细内容】
2021-11-30  Go语言中文网    Tags:slices 包   点击:(30)  评论:(0)  加入收藏
前言最近因为项目需要写了一段时间的 Go ,相对于 Java 来说语法简单同时又有着一些 Python 之类的语法糖,让人大呼”真香“。 但现阶段相对来说还是 Python 写的多一些,偶尔还...【详细内容】
2021-11-25  crossoverJie    Tags:Go   点击:(41)  评论:(0)  加入收藏
go-micro是基于 Go 语言用于开发的微服务的 RPC 框架,主要功能如下:服务发现,负载均衡 ,消息编码,请求/响应,Async Messaging,可插拔接口,最后这个功能牛p安装步骤安装proto...【详细内容】
2021-09-06    石老师小跟班  Tags:go-micro   点击:(214)  评论:(0)  加入收藏
GoLand 2021.2 EAP 5 现已发布。用户可以从工具箱应用程序中获得 EAP 构建,也可以从官方网站手动下载。并且从此 EAP 开始,只有拥有有效的 JetBrains 帐户才能加入该计划。手...【详细内容】
2021-06-29  IT实战联盟  今日头条  Tags:GoLand   点击:(188)  评论:(0)  加入收藏
作者:HDT3213今天给大家带来的开源项目是 Godis:一个用 Go 语言实现的 Redis 服务器。支持: 5 种数据结构(string、list、hash、set、sortedset) 自动过期(TTL) 发布订阅、地理位...【详细内容】
2021-06-18  HelloGitHub  今日头条  Tags:Go   点击:(131)  评论:(0)  加入收藏
统一规范篇合理规划目录本篇主要描述了公司内部同事都必须遵守的一些开发规矩,如统一开发空间,既使用统一的开发工具来保证代码最后的格式的统一,开发中对文件和代码长度的控制...【详细内容】
2021-05-18  1024课堂    Tags:Go语言   点击:(235)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条