
Заместитель на C++
Заместитель — это объект, который выступает прослойкой между клиентом и реальным сервисным объектом. Заместитель получает вызовы от клиента, выполняет свою функцию (контроль доступа, кеширование, изменение запроса и прочее), а затем передаёт вызов сервисному объекту.
Заместитель имеет тот же интерфейс, что и реальный объект, поэтому для клиента нет разницы — работать через заместителя или напрямую.
Сложность:
Популярность:
Применимость: Паттерн Заместитель применяется в C++ коде тогда, когда надо заменить настоящий объект его суррогатом, причём незаметно для клиентов настоящего объекта. Это позволит выполнить какие-то добавочные поведения до или после основного поведения настоящего объекта.
Признаки применения паттерна: Класс заместителя чаще всего делегирует всю настоящую работу своему реальному объекту. Заместители часто сами следят за жизненным циклом своего реального объекта.
Концептуальный пример
Этот пример показывает структуру паттерна Заместитель, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
main.cc: Пример структуры паттерна
#include <iostream> /** * Интерфейс Субъекта объявляет общие операции как для Реального Субъекта, так и * для Заместителя. Пока клиент работает с Реальным Субъектом, используя этот * интерфейс, вы сможете передать ему заместителя вместо реального субъекта. */ class Subject { public: virtual void Request() const = 0; }; /** * Реальный Субъект содержит некоторую базовую бизнес-логику. Как правило, * Реальные Субъекты способны выполнять некоторую полезную работу, которая к * тому же может быть очень медленной или точной – например, коррекция входных * данных. Заместитель может решить эти задачи без каких-либо изменений в коде * Реального Субъекта. */ class RealSubject : public Subject { public: void Request() const override { std::cout << "RealSubject: Handling request.\n"; } }; /** * Интерфейс Заместителя идентичен интерфейсу Реального Субъекта. */ class Proxy : public Subject { /** * @var RealSubject */ private: RealSubject *real_subject_; bool CheckAccess() const { // Некоторые реальные проверки должны проходить здесь. std::cout << "Proxy: Checking access prior to firing a real request.\n"; return true; } void LogAccess() const { std::cout << "Proxy: Logging the time of request.\n"; } /** * Заместитель хранит ссылку на объект класса РеальныйСубъект. Клиент может * либо лениво загрузить его, либо передать Заместителю. */ public: Proxy(RealSubject *real_subject) : real_subject_(new RealSubject(*real_subject)) { } ~Proxy() { delete real_subject_; } /** * Наиболее распространёнными областями применения паттерна Заместитель * являются ленивая загрузка, кэширование, контроль доступа, ведение журнала и * т.д. Заместитель может выполнить одну из этих задач, а затем, в зависимости * от результата, передать выполнение одноимённому методу в связанном объекте * класса Реального Субъект. */ void Request() const override { if (this->CheckAccess()) { this->real_subject_->Request(); this->LogAccess(); } } }; /** * Клиентский код должен работать со всеми объектами (как с реальными, так и * заместителями) через интерфейс Субъекта, чтобы поддерживать как реальные * субъекты, так и заместителей. В реальной жизни, однако, клиенты в основном * работают с реальными субъектами напрямую. В этом случае, для более простой * реализации паттерна, можно расширить заместителя из класса реального * субъекта. */ void ClientCode(const Subject &subject) { // ... subject.Request(); // ... } int main() { std::cout << "Client: Executing the client code with a real subject:\n"; RealSubject *real_subject = new RealSubject; ClientCode(*real_subject); std::cout << "\n"; std::cout << "Client: Executing the same client code with a proxy:\n"; Proxy *proxy = new Proxy(real_subject); ClientCode(*proxy); delete real_subject; delete proxy; return 0; }
Output.txt: Результат выполнения
Client: Executing the client code with a real subject: RealSubject: Handling request. Client: Executing the same client code with a proxy: Proxy: Checking access prior to firing a real request. RealSubject: Handling request. Proxy: Logging the time of request.