簡介 代理模式(Proxy Pattern)是一種結構型設計模式,用一個類來代理另一個類或幾個類的功能。 在代理模式中,我們創建具有現有對象的對象,以便向外界提供功能介面。 延遲初始化(虛擬代理)。如果你有一個偶爾使用的重量級服務對象,一直保持該對象運行會消耗系統資源時,可使用代理模式。 訪問控制( ...
簡介
代理模式(Proxy Pattern)是一種結構型設計模式,用一個類來代理另一個類或幾個類的功能。
在代理模式中,我們創建具有現有對象的對象,以便向外界提供功能介面。
延遲初始化(虛擬代理)。如果你有一個偶爾使用的重量級服務對象,一直保持該對象運行會消耗系統資源時,可使用代理模式。
訪問控制(保護代理)。如果你只希望特定客戶端使用服務對象,這裡的對象可以是操作系統中非常重要的部分,而客戶端則是各種已啟動的程式 (包括惡意程式), 此時可使用代理模式。
作用
- 為其他對象提供一種代理訪問的方式。
- 避免直接訪問可能帶來的問題,通過介面和代理來實現高擴展。
實現步驟
- 定義一個基礎介面,約定一些方法。
- 建立原始類,實現介面方法。
- 再建立代理類,也實現基礎介面。代理類調用原始類來實現功能。
UML
Java代碼
代理介面類
// Image.java 定義一個介面供代理和實際調用來使用
public interface Image {
void display();
}
功能代理類
// ProxyImage.java 代理類也實現了基礎介面
public class ProxyImage implements Image {
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
System.out.println("ProxyImage::display() " + fileName);
if (realImage == null) {
realImage = new RealImage(fileName);
}
// 代理類調用真實類的方法
realImage.display();
}
}
真實功能類
// RealImage.java 真實類也實現基礎代理介面
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
// 在初始化時執行內部邏輯
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("RealImage::display() " + fileName);
}
// 這個方法只是內部使用
private void loadFromDisk(String fileName) {
System.out.println("RealImage::loadFromDisk() " + fileName);
}
}
測試調用
/**
* 代理模式就是用一個類來代理另一個類或幾個類的功能,以便隔絕外部客戶和內部真實類
* 這樣真實類和調用方之間有一個代理屏障,保證了安全
* 同時真實的類如果初始化過,就不再初始化,提升了性能
*/
// 聲明代理類來執行真實類的能力
Image image = new ProxyImage("001.jpg");
// 代理類執行真實類的能力
image.display();
// 再調用一次,不會重覆實例化
image.display();
Go代碼
代理介面類
// Image.go 定義一個介面供代理和實際調用來使用
type Image interface {
Init(fileName string)
Display()
}
功能代理類
// ProxyImage.go 代理類也實現了基礎介面
type ProxyImage struct {
fileName string
// 直接聚合真實類
// realImage RealImage
// 聚合介面
realImage Image
}
// 設置文件名稱
func (p *ProxyImage) SetFileName(fileName string) {
p.fileName = fileName
}
func (p *ProxyImage) Display() {
fmt.Println("ProxyImage::Display() " + p.fileName)
if p.realImage == nil {
p.realImage = &RealImage{}
p.realImage.Init(p.fileName)
}
// 代理類調用真實類的方法
p.realImage.Display()
}
真實功能類
// RealImage.go 真實類也實現基礎代理介面
type RealImage struct {
fileName string
}
// 在初始化時執行內部邏輯
func (r *RealImage) Init(fileName string) {
r.fileName = fileName
r.LoadFromDisk(fileName)
}
func (r *RealImage) Display() {
fmt.Println("RealImage::Display() " + r.fileName)
}
// 這個方法只是內部使用
func (r *RealImage) LoadFromDisk(fileName string) {
fmt.Println("RealImage::LoadFromDisk() " + fileName)
}
測試調用
func main() {
fmt.Println("test start:")
/**
* 代理模式就是用一個類來代理另一個類或幾個類的功能,以便隔絕外部客戶和內部真實類
* 這樣真實類和調用方之間有一個代理屏障,保證了安全
* 同時真實的類如果初始化過,就不再初始化,提升了性能
*/
// 聲明代理類來執行真實類的能力
var image = &src.ProxyImage{}
image.SetFileName("001.jpg")
// 代理類執行真實類的能力
image.Display()
// 再調用一次,真實類不會重覆實例化
image.Display()
}
C代碼簡版
// simple_proxy.c
#include <stdio.h>
// 代理模式就是用一個類來代理另一個類或幾個類的功能,以便隔絕外部客戶和內部真實類
// 定義介面
typedef struct Interface
{
void (*method)(struct Interface *interface);
} Interface;
// 實現介面的具體類
typedef struct Concrete
{
void (*method)(struct Concrete *interface);
} Concrete;
void real_method(struct Concrete *interface)
{
printf("調用真實方法 real_method.\n");
}
// 代理類,繼承介面,聚合具體類實例
typedef struct Proxy
{
struct Interface *real_subject;
} Proxy;
// 代理類方法實現,通過聚合的具體類實例來調用具體類的方法
void proxy_method(struct Interface *interface)
{
struct Proxy *p = (struct Proxy *)interface;
p->real_subject->method((struct Interface *)p);
}
int main()
{
// 創建具體類實例
struct Concrete real_subject = {
.method = &real_method,
};
// 創建代理類實例並聚合具體類實例
struct Proxy proxy_instance = {
.real_subject = (struct Interface *)&real_subject,
};
// 將代理類的方法指針指向代理類的方法實現
struct Interface proxy_interface = {
.method = &proxy_method,
};
// 通過代理類的介面調用具體類方法
proxy_interface.method((struct Interface *)&proxy_instance);
return 0;
}
更多語言版本
不同語言實現設計模式:https://github.com/microwind/design-pattern