代理模式
定義
定義:為其物件提供一種代理以控制這個物件的訪問。通俗點講就是它在不改變原始類(或叫被代理類)程式碼的情況下,通過引入代理類來給原始類附加功能。
來點通俗的理解:
比如我們買火車票,除了火車站,很多代售點也是可以買的,代售點的作用就是代理模式
優點
1、代理模式在客戶端與目標物件之間起到一箇中介作用和保護目標物件的作用;
2、代理物件可以擴充套件目標物件的功能;
3、代理模式能將客戶端與目標物件分離,在一定程度上降低了系統的耦合度,增加了程式的可擴充套件性;
缺點
1、代理模式會造成系統設計中類的數量增加;
2、在客戶端和目標物件之間增加一個代理物件,會造成請求處理速度變慢;
3、增加了系統的複雜度;
應用場景
- 1、業務系統的非功能性需求開發
一些非功能性的業務需求,比如:監控、統計、鑑權、限流、事務、冪等、日誌。我們將這些附加功能與業務功能解耦,放到代理類中統一處理,讓程式設計師只需要關注業務方面的開發。
- 2、代理模式在RPC中的應用
RPC框架也可以看成是一種代理模式。
GoF的《設計模式》一書中把它稱作遠端代理。通過遠端代理,將網路通訊、資料編解碼等細節隱藏起來。客戶端使用RPC服務就像使用本地函式一樣,RPC服務的開發者也只需要開發業務邏輯,就像開發本地使用的函式一樣,不需要關注跟客戶端的互動細節。
- 3、代理模式在快取中的應用
對於一些介面的開發,有時候對於一個功能,我們會提供兩種介面,一種支援快取,一種不支援快取,對於需要實時資料的需求,我們讓其呼叫實時查詢介面,對於不需要實時資料的需求,我們讓其呼叫支援快取的介面。
簡單的做法就是介面寫兩個,一個支援快取的一個不支援快取,但是這樣我們的程式碼就有些臃腫了。
可以使用代理模式中的動態代理。舉個例子:
如果是基於Spring框架來開發的話,那就可以在AOP切面中完成介面快取的功能。在應用啟動的時候,我們從配置檔案中載入需要支援快取的介面,以及相應的快取策略(比如過期時間)等。當請求到來的時候,我們在AOP切面中攔截請求,如果請求中帶有支援快取的欄位(比如http://…?..&cached=true),我們便從快取(記憶體快取或者Redis快取等)中獲取資料直接返回。
程式碼實現
這裡藉助於大話設計模式中的追女孩的栗子:
小明喜歡小紅,但是害羞不好意思出面,所以拜託好朋友,小張,出面給小紅送禮物。
小明是追求者,小張就是小明的中間人,也就是代理。
type GiveGift interface {
GiveDolls() string
GiveFlowers() string
GiveChocolate() string
}
// 追求者
type Pursuit struct {
GirlName string
}
func NewGirl(name string) *Pursuit {
return &Pursuit{
GirlName: name,
}
}
func (ps *Pursuit) GiveDolls() string {
return fmt.Sprintf("%s-送你娃娃", ps.GirlName)
}
func (ps *Pursuit) GiveFlowers() string {
return fmt.Sprintf("%s-送你漂亮的鮮花", ps.GirlName)
}
func (ps *Pursuit) GiveChocolate() string {
return fmt.Sprintf("%s-送你巧克力", ps.GirlName)
}
// 代理也就是中間人
type Proxy struct {
Pursuit
}
func NewProxy(name string) *Pursuit {
return NewGirl(name)
}
func (pr *Proxy) GiveDolls() string {
return pr.GiveDolls()
}
func (pr *Proxy) GiveFlowers() string {
return pr.GiveFlowers()
}
func (pr *Proxy) GiveChocolate() string {
return pr.GiveChocolate()
}
最後放上一張結構圖
參考
【文中程式碼】https://github.com/boilingfrog/design-pattern-learning/tree/master/代理模式
【大話設計模式】https://book.douban.com/subject/2334288/
【極客時間】https://time.geekbang.org/column/intro/100039001
【代理模式】https://boilingfrog.github.io/2021/11/08/使用go實現代理模式/