Шаблон Заместитель позволяет контролировать доступ к заданному объекту, перехватывая все вызовы к этому объекту и прозрачно замещая его. Ни интерфейс, ни функциональность замещённого объекта с точки зрения клиента не меняются. Данный шаблон часто используется, если необходимо упростить или оптимизировать взаимодействие с объектом, скрывая несущественные для конкретной задачи подробности реализации.
На рис 3. показан дизайн шаблона Заместитель. И заместитель Proxy, и класс замещаемого объекта Subject реализуют общий интерфейс ISubject. Заместитель может агрегировать замещаемый объект или порождать локальные экземпляры этого объекта при необходимости. Как правило, клиент не имеет прямого доступа к замещаемому объекту.
Рис. 3. Дизайн шаблона Заместитель.
Перечислим некоторые разновидности шаблона Заместитель:
– Удалённый заместитель (remote proxy) обеспечивает связь с замещаемым объектом, который находится в другом адресном пространстве или на удалённой машине;
– Виртуальный заместитель (virtual proxy) реализует создание замещаемого объекта только тогда, когда он действительно необходим;
|
|
– Защищающий заместитель (protection proxy) проверяет, имеет ли вызывающий объект необходимые для выполнения запроса права.
Рассмотрим примера реализации виртуального заместителя для оптимизации работы с большими изображениями.
public interface IImage
{
void Display();
}
public class RealImage: IImage
{
private readonly string _filename;
public RealImage(string filename)
{
_filename = filename;
LoadImageFromDisk();
}
public void Display()
{
Console.WriteLine("Displaying " + _filename);
}
private void LoadImageFromDisk()
{
Console.WriteLine("Loading " + _filename);
}
}
public class ProxyImage: IImage
{
private RealImage _image;
private readonly string _filename;
public ProxyImage(string filename)
{
_filename = filename;
}
public void Display()
{
if (_image == null)
{
_image = new RealImage(_filename);
}
_image.Display();
}
}
Приведём клиентский код, работающий с виртуальным заместителем:
IImage image1 = new ProxyImage("HiRes_10MB_Photo1");
IImage image2 = new ProxyImage("HiRes_20MB_Photo2");
image1.Display(); // выполняется загрузка
image1.Display(); // загрузка не выполняется
image2.Display(); // выполняется загрузка
image2.Display(); // загрузка не выполняется
image1.Display(); // загрузка не выполняется