热门问题
时间线
聊天
视角
代理模式
来自维基百科,自由的百科全书
Remove ads
代理模式(英語:proxy pattern),是程式設計中的一種設計模式。所謂的代理者是指一個類別可以作為其它東西的介面。代理者可以作任何東西的介面:網絡連接、記憶體中的大物件、檔案或其它昂貴或無法複製的資源。

概述
著名的代理模式例子為參照計數(英語:reference counting)指標物件。當一個複雜物件的多份副本須存在時,代理模式可以結合享元模式以減少記憶體用量。典型作法是建立一個複雜物件及多個代理者,每個代理者會參照到原本的複雜物件。而作用在代理者的運算會轉送到原本物件。一旦所有的代理者都不存在時,複雜物件會被移除。
結構

在上面的UML類圖中,Proxy類實現了Subject介面,使它充當Subject對象的代替者。它維護一個參照(realSubject)至被代替的對象(RealSubject),使其可以轉發給它(realSubject.operation())。
序列圖展示了執行時互動:The Client對象通過合作於Proxy對象,來控制到RealSubject對象的訪問。在這個例子中,Proxy轉發請求至RealSubject,它辦理這個請求。
範例
下面是C++的例子:
import std;
using std::string;
using std::unique_ptr;
// Subject Interface
class Image {
public:
virtual void display() const = 0;
virtual ~Image() = default;
};
// Real Subject (expensive to load)
class RealImage : public Image {
private:
string filename;
public:
explicit RealImage(const string& file):
filename{file} {
loadFromDisk();
}
void display() const override {
std::println("Displaying image: {}", filename);
}
private:
void loadFromDisk() const {
std::println("Loading image from disk: {}", filename);
}
};
// Proxy (controls access to RealImage)
class ProxyImage : public Image {
private:
string filename;
mutable unique_ptr<RealImage> realImage; // lazily created
public:
explicit ProxyImage(const string& file):
filename{file} {}
void display() const override {
if (!realImage) {
std::println("(Proxy) Loading image on demand...");
realImage = std::make_unique<RealImage>(filename);
}
realImage->display();
}
};
// Client code
int main() {
Image* img = new ProxyImage("photo.png");
// First display (should load)
img->display();
// Second display (should use cached image)
img->display();
delete img;
return 0;
}
Remove ads
以下Java範例解釋惰性載入模式中的「虛擬代理」方法。ProxyImage 類別用來存取遠端方法。
import java.util.*;
interface Image {
public void displayImage();
}
//on System A
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadImageFromDisk();
}
private void loadImageFromDisk() {
System.out.println("Loading " + filename);
}
public void displayImage() {
System.out.println("Displaying " + filename);
}
}
//on System B
class ProxyImage implements Image {
private String filename;
private Image image;
public ProxyImage(String filename) {
this.filename = filename;
}
public void displayImage() {
if(image == null)
image = new RealImage(filename);
image.displayImage();
}
}
class ProxyExample {
public static void main(String[] args) {
Image image1 = new ProxyImage("HiRes_10MB_Photo1");
Image image2 = new ProxyImage("HiRes_10MB_Photo2");
image1.displayImage(); // loading necessary
image2.displayImage(); // loading necessary
}
}
程式的輸出為:
Loading HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo1
Loading HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo2
Remove ads
C#的例子:
using System;
namespace Proxy {
interface IImage {
void Display();
}
class RealImage : IImage {
public RealImage(string fileName) {
FileName = fileName;
LoadFromFile();
}
private void LoadFromFile() {
Console.WriteLine("Loading " + FileName);
}
public String FileName { get; private set; }
public void Display() {
Console.WriteLine("Displaying " + FileName);
}
}
class ProxyImage : IImage {
public ProxyImage(string fileName) {
FileName = fileName;
}
public String FileName { get; private set; }
private IImage image;
public void Display() {
if (image == null)
image = new RealImage(FileName);
image.Display();
}
}
class Program {
static void Main(string[] args) {
IImage image = new ProxyImage("HiRes_Image");
for (int i = 0; i < 10; i++)
image.Display();
}
}
}
程式的輸出為:
Loading HiRes_Image
Displaying HiRes_Image
Displaying HiRes_Image
Displaying HiRes_Image
Displaying HiRes_Image
Displaying HiRes_Image
Displaying HiRes_Image
Displaying HiRes_Image
Displaying HiRes_Image
Displaying HiRes_Image
Displaying HiRes_Image
Remove ads
from abc import ABC, abstractmethod
class Image(ABC):
@abstractmethod
def display(self): pass
class RealImage(Image):
def __init__(self, filename):
self.filename = filename
self.load_from_disk()
def load_from_disk(self):
print("Loading ", self.filename)
def display(self):
print("Displaying ", self.filename)
class ProxyImage(Image):
def __init__(self, filename):
self.filename = filename
self.image = None
def display(self):
if self.image is None:
self.image = RealImage(self.filename)
self.image.display()
def example():
image1 = ProxyImage("HiRes_10MB_Photo1")
image2 = ProxyImage("HiRes_10MB_Photo2")
image1.display()
image2.display()
image1.display()
image2.display()
其執行:
>>> example()
Loading HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo1
Loading HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo2
Remove ads
另見
參照
外部連結
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads
