Ответ
Паттерн Proxy (Заместитель) — это структурный паттерн, предоставляющий объект-заменитель или placeholder для другого объекта. Прокси контролирует доступ к оригинальному объекту, позволяя выполнять дополнительную логику до или после основного вызова.
Основные сценарии использования:
- Ленивая инициализация (Virtual Proxy): Отложить создание ресурсоёмкого объекта до момента реальной необходимости.
- Контроль доступа (Protection Proxy): Проверить права доступа перед вызовом методов реального объекта.
- Кеширование (Cache Proxy): Сохранять результаты дорогостоящих операций и возвращать кешированные данные.
- Логирование и мониторинг: Записывать вызовы методов, время выполнения.
- Удалённый доступ (Remote Proxy): Представлять объект, находящийся в другом адресном пространстве (например, при использовании удалённых сервисов).
Типы Proxy:
- Virtual Proxy – откладывает создание ресурсоемкого объекта.
- Protection Proxy – контролирует доступ к объекту.
- Remote Proxy – представляет объект в другом адресном пространстве.
- Smart Proxy – добавляет дополнительную логику (кеширование, логирование).
Пример (Virtual Proxy на C#):
// Интерфейс, общий для реального объекта и прокси
public interface IImage
{
void Display();
}
// Реальный, «тяжёлый» объект
public class RealImage : IImage
{
private string _fileName;
public RealImage(string fileName)
{
_fileName = fileName;
LoadFromDisk(); // Дорогая операция
}
private void LoadFromDisk() => Console.WriteLine($"Loading image '{_fileName}' from disk...");
public void Display() => Console.WriteLine($"Displaying image '{_fileName}'");
}
// Прокси-объект
public class ProxyImage : IImage
{
private RealImage _realImage;
private string _fileName;
public ProxyImage(string fileName) => _fileName = fileName;
public void Display()
{
// Создаём реальный объект только при первом вызове
if (_realImage == null)
{
_realImage = new RealImage(_fileName);
}
_realImage.Display();
}
}
// Использование
var image = new ProxyImage("high_res_photo.jpg");
// RealImage ещё не создан
image.Display(); // Вывод: "Loading image 'high_res_photo.jpg' from disk..." затем "Displaying image 'high_res_photo.jpg'"
image.Display(); // Вывод: "Displaying image 'high_res_photo.jpg'" (объект уже загружен)
Практическое применение: В .NET паттерн Proxy лежит в основе многих технологий, таких как:
- Entity Framework Core (ленивая загрузка навигационных свойств).
- МОК-объекты в юнит-тестах (например, в Moq или NSubstitute).
- WCF/Remoting клиенты для удалённых сервисов.
Ответ 18+ 🔞
Давай разберем эту проксю, а то звучит как что-то из шпионских фильмов, а на деле — просто хитрая обёртка, чтобы не париться.
Смотри, представь, что у тебя есть объект, который жрёт оперативку, как не в себя, или грузится с диска целую вечность. Создавать его сразу — всё равно что включать весь домофонный щиток, чтобы позвонить в одну квартиру. Идиотизм.
Вот тут и выходит на сцену Прокси (Заместитель). Это такой подставной чувак, который делает вид, что он и есть тот самый тяжелый объект. У него та же самая рожа (интерфейс), но внутри он — просто понторез.
Зачем это, блядь, нужно?
- Ленивая загрузка (Virtual Proxy): Не создавать объект, пока он реально не понадобится. Зачем грузить гигабайтную картинку, если пользователь может просто пролистать её и не открывать?
- Защита доступа (Protection Proxy): Как вышибала в клубе. Прежде чем пустить тебя к реальному объекту (методу), проверит твой access level. Не пройдёшь — получишь по ебалу.
- Кеширование (Cache Proxy): Запоминает результат дорогой операции. Следующий раз, когда спросят, не будет опять лезть в базу или считать десять минут, а тупо выдаст сохранённый ответ. Умно, да?
- Логирование: Чтобы потом, когда всё наебнётся, можно было посмотреть, кто, когда и какую хуйню вызывал.
- Удалённый доступ (Remote Proxy): Когда реальный объект сидит на другом сервере, а тебе надо с ним общаться так, будто он тут, рядом. Прокси берёт на себя всю грязную работу по сети.
Пример на C# (Ленивая загрузка картинки):
Вот смотри, как это выглядит в коде. Без прокси — сразу влетаем по полной, с прокси — только когда припрет.
// Это как договор. И реальная картинка, и её заместитель обещают уметь одно и то же.
public interface IImage
{
void Display();
}
// Настоящая, тяжёлая картинка. Её создание — боль.
public class RealImage : IImage
{
private string _fileName;
public RealImage(string fileName)
{
_fileName = fileName;
LoadFromDisk(); // Вот эта строка — пиздец какой долгий процесс!
}
private void LoadFromDisk() => Console.WriteLine($"Гружу картинку '{_fileName}' с диска... Овердохуища времени...");
public void Display() => Console.WriteLine($"Показываю картинку '{_fileName}'");
}
// А вот наш хитрожопый заместитель!
public class ProxyImage : IImage
{
private RealImage _realImage; // Ссылка на настоящую тяжёлую картинку. Пока её нет.
private string _fileName;
public ProxyImage(string fileName) => _fileName = fileName; // Создался мгновенно! Ничего не грузил!
public void Display()
{
// Ага, вот тут момент истины. Картинку просят показать.
// Если реальный объект ещё не создан — вот сейчас, блядь, и создадим.
if (_realImage == null)
{
_realImage = new RealImage(_fileName); // ТУТ происходит вся боль.
}
// А теперь делегируем показ уже созданному (или только что созданному) объекту.
_realImage.Display();
}
}
// Использование
var image = new ProxyImage("photo_of_my_vacation_in_4k.jpg");
// На этом этапе RealImage НЕ создан! Прокси — просто пустышка с названием файла.
Console.WriteLine("Прокси создан, все быстро и безболезненно.");
// Первый вызов — будет больно, но только один раз.
image.Display(); // Вывод: "Гружу картинку 'photo_of_my_vacation_in_4k.jpg' с диска..." -> "Показываю картинку..."
// Второй вызов — уже легко, объект-то уже есть!
image.Display(); // Вывод: "Показываю картинку 'photo_of_my_vacation_in_4k.jpg'"
Где это валяется в .NET? Да почти везде, если присмотреться!
- Entity Framework Core: Твои навигационные свойства (
List<Order>) часто — ленивые прокси. Они не грузят заказы из базы, пока ты к ним явно не обратишься. - Моки в тестах (Moq, NSubstitute): Это вообще чистейшие прокси-объекты, которые подменяют реальные сервисы и записывают, какие методы ты вызывал.
- Клиенты WCF: Когда ты вызываешь метод удалённого сервиса, твой локальный клиент — это прокси, который упаковывает вызов, шлёт его по сети и получает ответ.
Короче, паттерн — огонь. Позволяет делать умные оптимизации и контролировать доступ, не переписывая логику самого объекта. Просто надеваешь на него шапку-невидимку в виде прокси, и он начинает работать по-новому.