Заместитель

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

import (
    "fmt"
)

//Graphic is Subject
type Graphic interface {
    Draw()
}

//Image is RealSubject
type Image struct {
    FileName string
}

//Draw is Request()
func (im Image) Draw() {
    fmt.Println("draw " + im.FileName)
}

//ImageProxy is Proxy
type ImageProxy struct {
    FileName string
    _image   *Image
}

//GetImage creates a RealSubject
func (ip *ImageProxy) GetImage() *Image {
    if ip._image == nil {
        ip._image = &Image{ip.FileName}
    }
    return ip._image
}

//Draw is Request()
func (ip *ImageProxy) Draw() {
    ip.GetImage().Draw()
}

//Client
proxy := &ImageProxy{FileName: "1.png"}
//operation without creating a RealSubject
fileName := proxy.FileName
//forwarded to the RealSubject
proxy.Draw()

fmt.Println(fileName)


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

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

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

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

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

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