Autumn SALE
Заместитель

Заместитель на Ruby

Заместитель — это объект, который выступает прослойкой между клиентом и реальным сервисным объектом. Заместитель получает вызовы от клиента, выполняет свою функцию (контроль доступа, кеширование, изменение запроса и прочее), а затем передаёт вызов сервисному объекту.

Заместитель имеет тот же интерфейс, что и реальный объект, поэтому для клиента нет разницы — работать через заместителя или напрямую.

Сложность:

Популярность:

Применимость: Паттерн Заместитель применяется в Ruby коде тогда, когда надо заменить настоящий объект его суррогатом, причём незаметно для клиентов настоящего объекта. Это позволит выполнить какие-то добавочные поведения до или после основного поведения настоящего объекта.

Признаки применения паттерна: Класс заместителя чаще всего делегирует всю настоящую работу своему реальному объекту. Заместители часто сами следят за жизненным циклом своего реального объекта.

Концептуальный пример

Этот пример показывает структуру паттерна Заместитель, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.

main.rb: Пример структуры паттерна

# Интерфейс Субъекта объявляет общие операции как для Реального Субъекта, так и
# для Заместителя. Пока клиент работает с Реальным Субъектом, используя этот
# интерфейс, вы сможете передать ему заместителя вместо реального субъекта.
#
# @abstract
class Subject
  # @abstract
  def request
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

# Реальный Субъект содержит некоторую базовую бизнес-логику. Как правило,
# Реальные Субъекты способны выполнять некоторую полезную работу, которая к тому
# же может быть очень медленной или точной – например, коррекция входных данных.
# Заместитель может решить эти задачи без каких-либо изменений в коде Реального
# Субъекта.
class RealSubject < Subject
  def request
    puts 'RealSubject: Handling request.'
  end
end

# Интерфейс Заместителя идентичен интерфейсу Реального Субъекта.
class Proxy < Subject
  # @param [RealSubject] real_subject
  def initialize(real_subject)
    @real_subject = real_subject
  end

  # Наиболее распространёнными областями применения паттерна Заместитель
  # являются ленивая загрузка, кэширование, контроль доступа, ведение журнала и
  # т.д. Заместитель может выполнить одну из этих задач, а затем, в зависимости
  # от результата, передать выполнение одноимённому методу в связанном объекте
  # класса Реального Субъекта.
  def request
    return unless check_access

    @real_subject.request
    log_access
  end

  # @return [Boolean]
  def check_access
    puts 'Proxy: Checking access prior to firing a real request.'
    true
  end

  def log_access
    print 'Proxy: Logging the time of request.'
  end
end

# Клиентский код должен работать со всеми объектами (как с реальными, так и
# заместителями) через интерфейс Субъекта, чтобы поддерживать как реальные
# субъекты, так и заместителей. В реальной жизни, однако, клиенты в основном
# работают с реальными субъектами напрямую. В этом случае, для более простой
# реализации паттерна, можно расширить заместителя из класса реального субъекта.
#
# @param [Subject] subject
def client_code(subject)
  # ...

  subject.request

  # ...
end

puts 'Client: Executing the client code with a real subject:'
real_subject = RealSubject.new
client_code(real_subject)

puts "\n"

puts 'Client: Executing the same client code with a proxy:'
proxy = Proxy.new(real_subject)
client_code(proxy)

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.

Заместитель на других языках программирования

Заместитель на C# Заместитель на C++ Заместитель на Go Заместитель на Java Заместитель на PHP Заместитель на Python Заместитель на Rust Заместитель на Swift Заместитель на TypeScript