Заместитель

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

# Subject
class Graphic
    def initialize(file_name)
        @file_name = file_name
    end

    def get_file_name()
        return @file_name
    end
end

# RealSubject
class Image < Graphic
    def initialize(file_name)
        super(file_name)
    end

    # Request()
    def draw()
        puts "draw " + @file_name
    end
end

# Proxy
class ImageProxy < Graphic
    def initialize(file_name)
        super(file_name)
        @image = nil
    end

    def draw()
        get_image().draw()
    end

    def get_image()
        if @image == nil
            @image = Image.new(@file_name)
        end
        return @image
    end
end

# Client
proxy = ImageProxy.new("1.png")
# operation without creating a RealSubject
fileName = proxy.get_file_name()
# forwarded to the RealSubject
proxy.draw()

puts "fileName is #{fileName}"


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

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

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

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

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

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