Заступник

Аналогія

Відкрити двері з електронним замком можна за допомогою картки доступу (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.

Залишити коментар