设计模式 12
- 创建型模式(5):工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
- 结构型模式(7):适配器模式、桥接模式、组合模式、装饰者模式、外观模式、享元模式、代理模式
- 行为型模式(11):责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式
文章目录
- [设计模式 12](#设计模式 12)
-
- [代理模式(Proxy Pattern)](#代理模式(Proxy Pattern))
-
- [1 定义](#1 定义)
- [2 结构](#2 结构)
- [3 示例代码](#3 示例代码)
- [4 特点](#4 特点)
- [5 适用场景](#5 适用场景)
- [6 与其他模式的关系](#6 与其他模式的关系)
代理模式(Proxy Pattern)
1 定义
代理模式通过创建一个代理对象来控制对另一个对象的访问。代理对象具有与原对象相同的接口,客户端可以通过代理对象访问实际的服务对象。代理对象可以在不影响客户端的情况下,对请求进行预处理或后处理。
2 结构
代理模式的结构包含以下角色:
- Subject(抽象主题): 定义了代理类和真实类的公共接口。
- RealSubject(真实主题): 实现了抽象主题的接口,是代理所代表的真实对象。
- Proxy(代理): 实现了抽象主题接口,并持有一个真实主题对象的引用。代理对象可以在调用真实对象的操作前后执行一些操作。
UML 类图
scss
+-----------------+
| Subject | <--------- 抽象主题
+-----------------+ |
| + Request() | |
+-----------------+ |
^ |
| |
+-----------------+ +-----------------+
| Proxy | | RealSubject |
+-----------------+ +-----------------+
| - realSubject: | ------- | + Request() |
| RealSubject | +-----------------+
| + Request() |
+-----------------+
3 示例代码
假设我们有一个需要访问的图像文件对象。图像文件可能很大,所以我们希望在图像真正需要显示时才加载它。在这种情况下,我们可以使用代理模式。
抽象主题接口
csharp
// 抽象主题
public interface IImage
{
void Display();
}
真实主题类
csharp
// 真实主题类:真实的图像文件
public class RealImage : IImage
{
private readonly string _filename;
public RealImage(string filename)
{
_filename = filename;
LoadImageFromDisk(); // 模拟加载图像文件
}
private void LoadImageFromDisk()
{
Console.WriteLine($"Loading image from disk: {_filename}");
}
public void Display()
{
Console.WriteLine($"Displaying image: {_filename}");
}
}
代理类
csharp
// 代理类:代理图像
public class ProxyImage : IImage
{
private RealImage _realImage;
private readonly string _filename;
public ProxyImage(string filename)
{
_filename = filename;
}
public void Display()
{
if (_realImage == null)
{
_realImage = new RealImage(_filename); // 延迟加载
}
_realImage.Display();
}
}
客户端代码
csharp
class Program
{
static void Main(string[] args)
{
IImage image = new ProxyImage("test_image.jpg");
// 图像第一次显示时,代理对象会加载真实图像
image.Display();
// 图像再次显示时,不需要再次加载
image.Display();
}
}
在这个例子中:
- 抽象主题
IImage
: 定义了Display()
方法,所有图像对象都必须实现这个方法。 - 真实主题类
RealImage
: 实现了IImage
接口,并在构造函数中模拟加载图像文件。Display()
方法显示图像。 - 代理类
ProxyImage
: 同样实现了IImage
接口,持有一个RealImage
对象的引用。只有在需要时,才会加载真实的图像文件,执行延迟加载。
运行结果
运行上述代码,你会看到以下输出:
plaintext
Loading image from disk: test_image.jpg
Displaying image: test_image.jpg
Displaying image: test_image.jpg
在这个例子中,图像在第一次调用 Display()
时才会加载,之后的调用直接显示图像,无需再次加载。这就是代理模式的延迟加载(Lazy Loading)应用。
4 特点
-
优点:
-
控制对象访问: 可以在不影响客户端的情况下控制对目标对象的访问。
-
延迟加载: 通过代理可以实现对象的延迟初始化,节省资源。
-
权限控制: 可以通过代理实现对敏感对象的访问控制。
-
-
缺点:
-
增加复杂性: 增加了类的数量和系统的复杂性。
-
可能引入性能开销: 代理模式可能会引入额外的处理逻辑,导致性能开销。
-
5 适用场景
- 需要延迟加载的场景: 当对象的创建成本较高且不经常使用时。
- 远程对象访问: 通过网络访问远程对象时,可以使用代理来隐藏复杂性。
- 控制访问权限: 需要对对象的访问进行权限控制时。
- 智能引用代理: 在访问对象时附加一些额外操作,如引用计数、日志记录等。
6 与其他模式的关系
- 装饰器模式: 代理和装饰器都通过代理控制对象,但装饰器用于添加行为,而代理用于控制访问。
- 适配器模式: 适配器模式改变接口以适配另一系统,而代理模式不改变接口,只是控制访问。
代理模式在设计复杂系统时提供了非常灵活的对象管理方式,通过合理使用代理,可以有效地提升系统的性能和安全性。