← Назад к вопросам
Можно ли класс А проксировать классом В?
2.0 Middle🔥 121 комментариев
#SOLID и паттерны проектирования
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Да, класс А можно проксировать классом В. Это распространённый паттерн
Proxy паттерн — это структурный паттерн проектирования, который позволяет предоставить замену (суррогат) для другого объекта, контролируя доступ к нему. Класс В выступает как посредник для класса А.
Концепция
Проксирование означает, что класс В:
- Скрывает экземпляр класса А
- Делегирует вызовы методов к А
- Добавляет функциональность (логирование, кеширование, контроль доступа)
- Реализует тот же интерфейс, что и А
Простой пример: Static Proxy
// Интерфейс, который будут реализовывать оба класса
public interface DataService {
String getData();
void saveData(String data);
}
// Реальный класс А
public class RealDataService implements DataService {
@Override
public String getData() {
// Дорогостоящая операция (БД запрос)
System.out.println("Читаю из БД...");
return "Важные данные";
}
@Override
public void saveData(String data) {
System.out.println("Сохраняю в БД: " + data);
}
}
// Прокси класс В
public class DataServiceProxy implements DataService {
private RealDataService realService; // Ссылка на А
private String cachedData; // Добавляем функциональность
public DataServiceProxy() {
this.realService = new RealDataService();
}
@Override
public String getData() {
// Добавляем кеширование
if (cachedData == null) {
System.out.println("Кеш пуст, запрашиваю данные...");
cachedData = realService.getData();
} else {
System.out.println("Возвращаю из кеша");
}
return cachedData;
}
@Override
public void saveData(String data) {
System.out.println("[ПРОКСИ] Логирую сохранение: " + data);
realService.saveData(data);
cachedData = null; // Инвалидируем кеш
}
}
// Использование
public class Main {
public static void main(String[] args) {
DataService service = new DataServiceProxy();
System.out.println(service.getData()); // Кеш пуст, запрашиваю...
System.out.println(service.getData()); // Возвращаю из кеша
service.saveData("Новые данные");
System.out.println(service.getData()); // Кеш пуст, запрашиваю...
}
}
Вывод:
Кеш пуст, запрашиваю данные...
Читаю из БД...
Важные данные
Возвращаю из кеша
Важные данные
[ПРОКСИ] Логирую сохранение: Новые данные
Сохраняю в БД: Новые данные
Кеш пуст, запрашиваю данные...
Читаю из БД...
Важные данные
Dynamic Proxy (Отражение)
Для более гибкого подхода используй JDK Dynamic Proxy:
public class LoggingInvocationHandler implements InvocationHandler {
private Object realObject; // Объект А
public LoggingInvocationHandler(Object realObject) {
this.realObject = realObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("[LOG] Вызов метода: " + method.getName());
// Делегируем реальному объекту
Object result = method.invoke(realObject, args);
System.out.println("[LOG] Метод завершён: " + method.getName());
return result;
}
}
// Использование
DataService realService = new RealDataService();
DataService proxy = (DataService) Proxy.newProxyInstance(
DataService.class.getClassLoader(),
new Class[]{DataService.class},
new LoggingInvocationHandler(realService)
);
proxy.getData(); // [LOG] Вызов метода: getData...
Когда использовать Proxy
| Сценарий | Описание |
|---|---|
| Lazy Loading | Создавать объект только когда он действительно нужен |
| Access Control | Проверка прав доступа перед вызовом метода |
| Logging/Monitoring | Логирование вызовов и времени выполнения |
| Caching | Кешировать результаты дорогостоящих операций |
| Remote Objects | Spring AOP, RMI, веб-сервисы |
Static vs Dynamic Proxy
| Тип | Плюсы | Минусы |
|---|---|---|
| Static | Простой, быстрый, понятный | Нужно писать для каждого класса |
| Dynamic | Универсальный, переиспользуемый | Медленнее, сложнее отладка |
Вывод
Да, класс В может проксировать класс А. В Java это делается:
- Static Proxy — явное написание класса-посредника
- Dynamic Proxy — через
Proxy.newProxyInstance()иInvocationHandler - CGLIB/ByteBuddy — для проксирования классов без интерфейсов (Spring AOP)
- Annotation-based — через
@Transactional,@Cacheable(Spring Framework)