golang设计模式系列(十一)-代理模式

代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

优点:

代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;代理对象可以扩展目标对象的功能;代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性

缺点:

代理模式会造成系统设计中类的数量增加在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;增加了系统的复杂度;

代理模式的结构与实现

代理模式的结构比较简单,主要是通过定义一个继承抽象主题的代理来包含真实主题,从而实现对真实主题的访问,下面来分析其基本结构和实现方法。

1. 模式的结构

代理模式的主要角色如下。

抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。代理模式的结构图

在代码中,一般代理会被理解为代码增强,实际上就是在原代码逻辑前后增加一些代码逻辑,而使调用者无感知。

代理模式的效果

代理模式在访问对象时引入了一定程度的间接性。根据代理的类型,附加的间接性有多种用途:

1)Remote Proxy可以隐藏一个对象存在于不同地址空间的事实。

2)virtual Proxy可以进行最优化,例如根据需要创建对象。

3)Protection Proxy和Smart Reference都允许在访问一个对象时有一些附加的事务处理(Housekeeping task)。

代理模式还可以对用户隐藏另外一种称为copy-on-write的优化方式(linux内核中大量使用),这种优化和根据需要创建对象有关。拷贝一个庞大而复杂的对象是一种开销很大的操作,如果这个拷贝根本就没有被修改,那么这开销就没有必要。用代理延迟这一拷贝过程,我们可以保证只有当这个对象被修改的时候才对它进行拷贝。

这个建造者实现了Builder :

package Proxy import ( "errors" "sync" ) type server interface { handleRequest(string, string) (int, string) } type RealRequest struct {} func (request *RealRequest) handleRequest(url string, method string) (int, error) { if url == "zhihu.com" && method == "post" { return 200, nil } return 404, errors.New("not find, 404") } type ngx_http_proxy_module struct { request *RealRequest maxRequestNum int handleRequestMap map[string]int } var instance *ngx_http_proxy_module var once sync.Once func GetNgxProxyInstance(maxRequestNum int) *ngx_http_proxy_module{ once.Do(func() { instance = &ngx_http_proxy_module{ request : &RealRequest{}, maxRequestNum: maxRequestNum, handleRequestMap:make(map[string]int, 0), } }) return instance } func (nginx *ngx_http_proxy_module) check(url string) error { if _, ok := nginx.handleRequestMap[url]; !ok { return nil } if nginx.handleRequestMap[url] >= nginx.maxRequestNum { return errors.New("the num of request more than limit") } return nil } func (nginx *ngx_http_proxy_module) addRequstCount(url string) { nginx.handleRequestMap[url] = nginx.handleRequestMap[url] + 1 } func (nginx *ngx_http_proxy_module) HandleRequest(url string, method string) (int, error){ if err := nginx.check(url); err != nil { return 403, err } nginx.addRequstCount(url) return nginx.request.handleRequest(url, method)

main:

package main import ( "./Proxy" "fmt" ) func main() { nginx := Proxy.GetNgxProxyInstance(3) url1 := "google.com" url2 := "baidu.com" fmt.Println(nginx.HandleRequest(url1, "get")) fmt.Println(nginx.HandleRequest(url1, "post")) fmt.Println(nginx.HandleRequest(url2, "post")) fmt.Println(nginx.HandleRequest(url2, "post")) fmt.Println(nginx.HandleRequest("zhihu.com", "post")) fmt.Println(nginx.HandleRequest("zhihu.com", "post")) fmt.Println(nginx.HandleRequest("zhihu.com", "post")) fmt.Println(nginx.HandleRequest("zhihu.com", "post")) fmt.Println(nginx.HandleRequest("zhihu.com", "post")) fmt.Println(nginx.HandleRequest("zhihu.com", "post")) fmt.Println(nginx.HandleRequest(url2, "post")) return }

该模式的使用场景:

远程代理。虚拟代理。Copy-on-Write 代理。保护(Protect or Access)代理。Cache代理。防火墙(Firewall)代理。同步化(Synchronization)代理。智能引用(Smart Reference)代理。