Заместитель

Паттерны проектирования / Структурные паттерны
image

type
  IImage = interface
    procedure Display;
  end;

  TRealImage = class(TInterfacedObject,
    IImage)
  private
    FFileName: string;
  public
    constructor Create(
      const AFileName: string);
    procedure Display;
  end;

  //proxy delays the heavy object
  //until it is really needed
  TImageProxy = class(TInterfacedObject,
    IImage)
  private
    FFileName: string;
    FReal: IImage;
  public
    constructor Create(
      const AFileName: string);
    procedure Display;
  end;

constructor TRealImage.Create(
  const AFileName: string);
begin
  FFileName := AFileName;
  WriteLn('loading ', FFileName);
end;

procedure TRealImage.Display;
begin
  WriteLn('display ', FFileName);
end;

constructor TImageProxy.Create(
  const AFileName: string);
begin
  FFileName := AFileName;
end;

procedure TImageProxy.Display;
begin
  if FReal = nil then
    FReal := TRealImage.Create(FFileName);
  FReal.Display;
end;

var
  Image: IImage;
begin
  Image := TImageProxy.Create('photo.png');
  WriteLn('proxy created, nothing loaded');

  Image.Display;
  //loading photo.png
  //display photo.png
end.


Подменяет другой объект для контроля доступа к нему. Заместитель реализует интерфейс первоначального объекта.
Read more

Задача. В документе много больших картинок. Если программа загружает их все при открытии документа, открытие идёт медленно, хотя пользователь видит только первую страницу. Код, который показывает картинки, должен остаться прежним. Но загрузка должна ждать, пока картинка действительно понадобится.

Идея. Заместитель встаёт на место другого объекта - реального субъекта. Интерфейс у них одинаковый, поэтому клиент не видит между ними разницы. Заместитель решает, когда и как пользоваться реальным субъектом. Этот вид, виртуальный заместитель, создаёт реальный субъект только при первом запросе, а потом передаёт ему каждый вызов. Другие виды заместителей проверяют права доступа, держат кэш или связываются с объектом на другом компьютере.

Как читать пример. Реальный субъект - это изображение, которое дорого создавать. Заместитель хранит только имя файла и пустое место под изображение. В большинстве языков клиент сначала спрашивает имя файла, и заместитель отвечает сам. Когда клиент просит нарисовать изображение, заместитель создаёт настоящее изображение, запоминает его и передаёт вызов. Клиент работает только с заместителем. В некоторых языках вывод показывает ещё и момент, когда настоящее изображение загружается.

Когда применять. Заместитель нужен, чтобы управлять доступом к объекту, не меняя ни сам объект, ни его клиентов. Типичные задачи - отложить дорогое создание, проверить права или посчитать вызовы. Если объект дёшев и нужен всегда, заместитель ни к чему: лишний уровень только замедляет код.

Частая ошибка. Не сохранить созданный объект. Тогда заместитель создаёт новый реальный субъект при каждом вызове, и вся экономия пропадает.