Аналогія
Відкрити двері з електронним замком можна за допомогою картки доступу (access card) або кнопки обходу системи безпеки. Тобто основна функціональність дверей – відкритися, а поверх неї може бути ще якась функціональність – «заступник».
Стисло
За допомогою шаблону “Заступник” клас представляє функціональність іншого класу.
Вікіпедія
У найбільш загальної формі «Заступник» – це клас, що функціонує як інтерфейс до чогось. Це оболонка або об’єкт-агент, який викликає клієнт для отримання доступу до іншого, «справжнього» об’єкта. «Заступник» може просто переадресовувати запити до цього об’єкта, а може надавати додаткову логіку: кешування даних при інтенсивному виконанні операцій або споживанні ресурсів цим об’єктом; перевірка попередніх умов (preconditions) до виклику виконання операцій цим об’єктом.
Приклад
Реалізуємо інтерфейс двері та самі двері:
interface Door
{
public function open();
public function close();
}
class LabDoor implements Door
{
public function open()
{
echo "Opening lab door";
}
public function close()
{
echo "Closing the lab door";
}
}
Зробимо «заступника», щоб двері могли виконувати захисну функцію:
class Security
{
protected $door;
public function __construct(Door $door)
{
$this->door = $door;
}
public function open($password)
{
if ($this->authenticate($password)) {
$this->door->open();
} else {
echo "Big no! It ain't possible.";
}
}
public function authenticate($password)
{
return $password === '$ecr@t';
}
public function close()
{
$this->door->close();
}
}
Використання:
$ door = New Security (New LabDoor ());
$door->open('invalid'); // Big no! It ain't possible.
$door->open('$ecr@t'); // Opening lab door
$door->close(); // Closing lab door
Ще один приклад пов’язані з реалізацією перетворювача даних (data-mapper). За допомогою цього шаблону я недавно зробив ODM (Object Data Mapper) MongoDB. Я написав “заступника” навколо mongo-класів, скориставшись чарівним методом __call(). Всі виклики методів проходили до оригінальних mongo-класів через «заступника», а результати поверталися як є. Тільки у випадку з find або findOne дані перетворювалися на об’єкти необхідного класу, які поверталися замість Cursor.