Что это такое
Паттерн Proxy (заместитель) ставит перед реальным объектом подставного двойника с тем же интерфейсом. Вызывающий код общается с заместителем так, будто это настоящий объект; заместитель сам решает, когда и как обратиться к оригиналу.
Типичные задачи заместителя: кэширование ответов, проверка доступа, откладывание дорогого создания объекта, подсчёт вызовов.
Пример: кэширующий заместитель
Настоящий сервис погоды работает медленно. Заместитель отвечает на повторные вопросы из своего кэша и обращается к сервису только за новыми — за тем же самым интерфейсом.
Двойник, который запоминает
Первый вопрос про Париж доходит до удалённого сервиса; на второй отвечает кэш — строка «обращение к удалённому сервису» печатается только один раз.
Вывод: программа на Go и захваченный вывод
package main
import "fmt"
type Weather interface {
Forecast(city string) string
}
// Настоящий сервис медленный и дорогой.
type WeatherService struct{}
func (WeatherService) Forecast(city string) string {
fmt.Println(" (обращение к удалённому сервису...)")
return "солнечно в городе " + city
}
// Заместитель стоит впереди и кэширует ответы.
type CachedWeather struct {
service WeatherService
cache map[string]string
}
func (c *CachedWeather) Forecast(city string) string {
if answer, ok := c.cache[city]; ok {
return answer + " (из кэша)"
}
answer := c.service.Forecast(city)
c.cache[city] = answer
return answer
}
func main() {
w := &CachedWeather{cache: map[string]string{}}
fmt.Println(w.Forecast("Париж"))
fmt.Println(w.Forecast("Париж"))
}
Когда его применять
Применяйте, чтобы добавить кэширование, контроль доступа, ленивую загрузку или учёт вызовов перед тем, что вы не можете или не должны менять — особенно перед удалёнными или дорогими ресурсами.
Не применяйте, когда объект принадлежит вам и поведение должно жить внутри него. Заместитель управляет доступом; декоратор добавляет поведение слоями — выбирайте по намерению.
Плюсы и минусы
Плюсы: вызывающий код вообще не нужно менять; дорогая работа пропускается или контролируется в одном месте.
Минусы: скрытое поведение — вызывающий код может получить ответ из кэша, не зная об этом; устаревший кэш и неожиданные отказы приходится отлаживать за безобидным на вид интерфейсом.