代理模式是通过创建一个代理对象,来控制对另一个对象的访问。代理对象和被代理对象实现了相同的接口,因此对客户端而言,它们是可以互换的。客户端通过调用代理对象的方法来访问被代理对象,代理对象可以在调用被代理对象之前或之后执行一些额外的操作,比如记录日志、实现缓存等。
代理模式通常用于以下场景:
远程代理:客户端通过代理对象访问远程的对象,代理对象将请求发送到远程对象,并将结果返回给客户端。
虚拟代理:在客户端访问一个复杂对象时,代理对象可以先返回一个占位符,等到真正需要使用时再创建真实的对象,以节省资源。
安全代理:代理对象可以控制客户端对被代理对象的访问,比如限制访问权限。
1、场景设计
实现场景:Image 接口定义了 display() 方法,RealImage 类实现了 Image 接口,并在其构造函数中加载了指定的文件。ProxyImage 类也实现了 Image 接口,并在其 display() 方法中判断实际的 RealImage 对象是否已经创建。如果没有创建,则创建一个新的 RealImage 对象,并调用其 display() 方法;如果已经创建,则直接调用 RealImage 对象的 display() 方法。通过使用代理模式,在实际对象创建之前对其进行延迟加载,从而提高应用程序的性能。
2、C++实现
#include <iostream>
#include <string>
using namespace std;
// Subject 接口
class Image {
public:
virtual void display() = 0;
};
// RealSubject 类
class RealImage : public Image {
public:
RealImage(std::string file_name) : m_file_name(file_name) {loadFromDisk(file_name);}
void display() override {
std::cout << "Displaying " << m_file_name << std::endl;
}
void loadFromDisk(std::string file_name){
std::cout << "Loading " << file_name << std::endl;
}
private:
std::string m_file_name;
};
// Proxy 类
class ProxyImage : public Image {
public:
ProxyImage(std::string file_name) : m_file_name(file_name) {}
void display() override {
if(real_image_ == NULL){
real_image_ = new RealImage(m_file_name);
}
real_image_->display();
}
private:
RealImage* real_image_ = NULL;
std::string m_file_name;
};
int main() {
Image* image = new ProxyImage("test.jpg");
// 第一次访问,实际的 Image 对象还没有创建
image->display();
// 第二次访问,实际的 Image 对象已经创建了,因此不会再次加载
image->display();
delete image;
return 0;
}
3、Java实现
package structuralpattern.proxy;
// Subject 接口
interface Image {
void display();
}
// RealSubject 类
class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
private void loadFromDisk(String fileName) {
System.out.println("Loading " + fileName);
}
}
// Proxy 类
class ProxyImage implements Image {
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(fileName);
}
realImage.display();
}
}
public class ProxyDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test.jpg");
// 第一次访问,实际的 Image 对象还没有创建
image.display();
// 第二次访问,实际的 Image 对象已经创建了,因此不会再次加载
image.display();
}
}