GoLang设计模式24 - 代理模式

代理模式是一种结构型设计模式。这种模式建议在访问对象时,添加一个额外的控制层,以便更灵活智能得对访问进行管理。

在这种模式中,会实现主对象的接口创建一个新的代理类。这让我们在执行主对象的逻辑前可以做一些额外的行为。看两个例子吧:

1. 信用卡可以视为是银行账户的代理。它的操作逻辑和银行账户相同,但却更容易使用。
2. 诸如Nginx这样的web服务器可以视为是应用服务器的代理,它可以起到如下的作用:
* 控制对应用服务器的访问,比如执行限流
* 做一些额外的动作,比如做一些缓存

看下代理模式的UML类图:

简单介绍下类图中的成员:

* `Subject`: 代表了主对象类(`realSubject`)和代理类(`proxy`)都需要实现的接口
* `Proxy`: 代表了代理类,在代理类中会嵌入`realSubject`实例,在它自己做完对请求的处理后,会将请求传递给`realSubject`实例进行操作
* `RealSubject`: 主对象类,包含了真实的业务逻辑,在代理模式中被置于代理类之后
* `Client`: 场景类,和代理类及主对象类都进行交互,因为二者实现了相同的接口

下面是前面介绍的nginx和应用服务器的例子所对应的类图:

下面是代码:

server.go:

1
2
3
type server interface {
    handleRequest(string, string) (int, string)
}

application.go

1
2
3
4
5
6
7
8
9
10
11
12
type application struct {
}
 
func (a *application) handleRequest(url, method string) (int, string) {
    if url == "/app/status" && method == "GET" {
        return 200, "Ok"
    }
    if url == "/create/user" && method == "POST" {
        return 201, "User Created"
    }
    return 404, "Not Ok"
}

nginx.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
type nginx struct {
    application       *application
    maxAllowedRequest int
    rateLimiter       map[string]int
}
 
func newNginxServer() *nginx {
    return &nginx{
        application:       &application{},
        maxAllowedRequest: 2,
        rateLimiter:       make(map[string]int),
    }
}
 
func (n *nginx) handleRequest(url, method string) (int, string) {
    allowed := n.checkRateLimiting(url)
    if !allowed {
        return 403, "Not Allowed"
    }
    return n.application.handleRequest(url, method)
}
 
func (n *nginx) checkRateLimiting(url string) bool {
    if n.rateLimiter[url] == 0 {
        n.rateLimiter[url] = 1
    }
    if n.rateLimiter[url] > n.maxAllowedRequest {
        return false
    }
    n.rateLimiter[url] = n.rateLimiter[url] + 1
    return true
}

main.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func main() {
    nginxServer := newNginxServer()
    appStatusURL := "/app/status"
    createUserURL := "/create/user"
    httpCode, body := nginxServer.handleRequest(appStatusURL, "GET")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
    httpCode, body = nginxServer.handleRequest(appStatusURL, "GET")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
    httpCode, body = nginxServer.handleRequest(appStatusURL, "GET")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
    httpCode, body = nginxServer.handleRequest(createUserURL, "POST")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
    httpCode, body = nginxServer.handleRequest(createUserURL, "GET")
    fmt.Printf("\nUrl: %s\nHttpCode: %d\nBody: %s\n", appStatusURL, httpCode, body)
}

输出内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Url: /app/status
HttpCode: 200
Body: Ok
 
Url: /app/status
HttpCode: 200
Body: Ok
 
Url: /app/status
HttpCode: 403
Body: Not Allowed
 
Url: /app/status
HttpCode: 201
Body: User Created
 
Url: /app/status
HttpCode: 404
Body: Not Ok

代码已上传至GitHub: zhyea / go-patterns / proxy-pattern

END!!

 

posted @   robin·张  阅读(435)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
点击右上角即可分享
微信分享提示