23种设计模式之《代理模式(Proxy)》在c#中的应用及理解
程序设计中的主要设计模式通常分为三大类,共23种:
1. 创建型模式(Creational Patterns)
-
单例模式(Singleton):确保一个类只有一个实例,并提供全局访问点。
-
工厂方法模式(Factory Method):定义创建对象的接口,由子类决定实例化哪个类。
-
抽象工厂模式(Abstract Factory):提供一个创建一系列相关或依赖对象的接口,而无需指定具体类。
-
建造者模式(Builder):将一个复杂对象的构建与其表示分离,使同样的构建过程可以创建不同的表示。
-
原型模式(Prototype):通过复制现有对象来创建新对象。
2. 结构型模式(Structural Patterns)
-
适配器模式(Adapter):将一个类的接口转换成客户希望的另一个接口。
-
桥接模式(Bridge):将抽象部分与实现部分分离,使它们可以独立变化。
-
组合模式(Composite):将对象组合成树形结构以表示“部分-整体”的层次结构。
-
装饰器模式(Decorator):动态地给对象添加职责,相比生成子类更为灵活。
-
外观模式(Facade):为子系统中的一组接口提供一个统一的接口。
-
享元模式(Flyweight):通过共享技术有效地支持大量细粒度对象。
-
代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。
3. 行为型模式(Behavioral Patterns)
-
责任链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者与接收者耦合。
-
命令模式(Command):将请求封装为对象,使你可以用不同的请求对客户进行参数化。
-
解释器模式(Interpreter):给定一个语言,定义其文法的一种表示,并定义一个解释器。
-
迭代器模式(Iterator):提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部表示。
-
中介者模式(Mediator):定义一个中介对象来封装一系列对象之间的交互。
-
备忘录模式(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
-
观察者模式(Observer):定义对象间的一对多依赖关系,当一个对象改变状态时,所有依赖者都会收到通知并自动更新。
-
状态模式(State):允许对象在其内部状态改变时改变其行为。
-
策略模式(Strategy):定义一系列算法,将它们封装起来,并使它们可以互相替换。
-
模板方法模式(Template Method):定义一个操作中的算法骨架,将一些步骤延迟到子类中。
-
访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作,使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
4.代理模式(Proxy Pattern)简介
代理模式是一种结构型设计模式,它允许你提供一个代理对象来控制对另一个对象的访问。代理对象通常会在客户端和目标对象之间充当中间人,用于延迟加载、访问控制、日志记录等。
代理模式的主要角色:
-
Subject(抽象主题):定义真实对象和代理对象的共同接口,客户端通过该接口与真实对象交互。
-
RealSubject(真实主题):实现抽象主题接口,是代理对象所代表的真实对象。
-
Proxy(代理):实现抽象主题接口,并持有对真实对象的引用。代理对象可以在调用真实对象之前或之后执行一些额外的操作。
5.代理模式的适用场景:
-
延迟加载(Lazy Loading):当创建对象的开销较大时,可以使用代理模式延迟对象的创建。
-
访问控制:代理可以控制对真实对象的访问权限。
-
日志记录:代理可以在调用真实对象的方法前后记录日志。
-
远程代理:代理可以代表远程对象,隐藏网络通信的细节。
6.C# 代码示例
下面是一个简单的C#示例,展示了如何使用代理模式来实现延迟加载。
csharp
using System;
// 抽象主题接口
public interface IImage
{
void Display();
}
// 真实主题类
public class RealImage : IImage
{
private string _fileName;
public RealImage(string fileName)
{
_fileName = fileName;
LoadImageFromDisk();
}
private void LoadImageFromDisk()
{
Console.WriteLine("Loading image: " + _fileName);
}
public void Display()
{
Console.WriteLine("Displaying image: " + _fileName);
}
}
// 代理类
public class ProxyImage : IImage
{
private RealImage _realImage;
private string _fileName;
public ProxyImage(string fileName)
{
_fileName = fileName;
}
public void Display()
{
if (_realImage == null)
{
_realImage = new RealImage(_fileName);
}
_realImage.Display();
}
}
// 客户端代码
public class Client
{
public static void Main(string[] args)
{
IImage image = new ProxyImage("test_image.jpg");
// 图像尚未加载
Console.WriteLine("Image will be loaded and displayed now.");
image.Display();
// 图像已经加载,无需再次加载
Console.WriteLine("Image will be displayed again.");
image.Display();
}
}
7.代码解析
-
IImage 接口:定义了
Display
方法,RealImage
和ProxyImage
都实现了这个接口。 -
RealImage 类:这是真实的对象,负责加载和显示图像。在构造函数中,它会从磁盘加载图像。
-
ProxyImage 类:这是代理类,它也实现了
IImage
接口。它持有一个RealImage
的引用,并在Display
方法中控制对RealImage
的访问。当Display
方法被调用时,代理会检查RealImage
是否已经创建,如果没有,则创建它并调用其Display
方法。 -
Client 类:客户端代码通过
ProxyImage
来访问RealImage
。第一次调用Display
时,RealImage
会被创建并加载图像。第二次调用时,由于RealImage
已经存在,代理会直接调用它的Display
方法,而不会再次加载图像。
8.总结
代理模式通过引入一个代理对象来控制对真实对象的访问,从而可以在不改变客户端代码的情况下,增加额外的功能(如延迟加载、访问控制等)。在实际应用中,代理模式可以用于多种场景,如远程代理、虚拟代理、保护代理等。