Pełnomocnik to strukturalny wzorzec projektowy według którego obiekt-usługodawca używany przez klienta jest zastępowany przez obiekt zastępczy, zwany pełnomocnikiem. Pełnomocnik przechwytuje żądania od klienta, wykonuje jakąś pracę (kontrola dostępu, zarządzanie pamięcią podręczną, itp.) a następnie przekazuje żądanie usługodawcy.
Obiekt będący pełnomocnikiem ma ten sam interfejs co usługodawca, co czyni go wymienialnym z obiektem usługodawcy dotychczas przekazywanym klientowi.
Przykład koncepcyjny
Serwer webowy, jak Nginx, może pełnić rolę pośrednika dla serwera aplikacji:
Kontroluje dostęp do serwera aplikacyjnego.
Steruje szybkością transmisji.
Może przechowywać żądania w swej pamięci podręcznej.
server.go: Podmiot
package main
type server interface {
handleRequest(string, string) (int, string)
}
nginx.go: Pośrednik
package main
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
}
application.go: Prawdziwy podmiot
package main
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"
}
main.go: Kod klienta
package main
import "fmt"
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)
}
output.txt: Wynik działania
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