Найти в Дзене
Java

🧠 Хитрая задача для Java-разработчиков: “Зеркальная фабрика

🧠 Хитрая задача для Java-разработчиков: “Зеркальная фабрика” 📌 Условие: Реализуйте абстрактную фабрику MirrorFactory, которая: - При создании объекта класса T возвращает прокси, который повторяет все методы оригинального объекта - Но дополнительно логирует имя каждого вызванного метода и автоматически вызывает метод с тем же именем у другого объекта (его зеркала) 🎯 Иными словами: MyService original = new MyService(); MyService mirror = new MyService(); MyService proxy = MirrorFactory.create(original, mirror); proxy.doWork(); // Лог: // doWork() called // original.doWork() вызван // mirror.doWork() вызван ❗️**Ограничения:** - Классы могут быть любыми, но должны реализовывать интерфейсы - Использовать только стандартные средства Java (рефлексия, Proxy, `InvocationHandler`) - Методы с одинаковым именем и сигнатурой должны быть вызваны у обоих объектов ✅ Решение: ```java import java.lang.reflect.*; public class MirrorFactory { @SuppressWarnings("unchecked") public static <T> T

🧠 Хитрая задача для Java-разработчиков: “Зеркальная фабрика”

📌 Условие:

Реализуйте абстрактную фабрику MirrorFactory, которая:

- При создании объекта класса T возвращает прокси, который повторяет все методы оригинального объекта

- Но дополнительно логирует имя каждого вызванного метода и автоматически вызывает метод с тем же именем у другого объекта (его зеркала)

🎯 Иными словами:

MyService original = new MyService();

MyService mirror = new MyService();

MyService proxy = MirrorFactory.create(original, mirror);

proxy.doWork();

// Лог:

// doWork() called

// original.doWork() вызван

// mirror.doWork() вызван

❗️**Ограничения:**

- Классы могут быть любыми, но должны реализовывать интерфейсы

- Использовать только стандартные средства Java (рефлексия, Proxy, `InvocationHandler`)

- Методы с одинаковым именем и сигнатурой должны быть вызваны у обоих объектов

✅ Решение:

```java

import java.lang.reflect.*;

public class MirrorFactory {

@SuppressWarnings("unchecked")

public static <T> T create(T original, T mirror) {

Class<?> clazz = original.getClass().getInterfaces()[0];

return (T) Proxy.newProxyInstance(

clazz.getClassLoader(),

new Class[]{clazz},

new InvocationHandler() {

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

System.out.println(method.getName() + "() called");

Object result1 = method.invoke(original, args);

Object result2 = method.invoke(mirror, args);

return result1; // приоритет оригиналу

}

});

}

}

```

Пример использования:

```java

interface MyService {

void doWork();

}

class MyServiceImpl implements MyService {

public void doWork() {

System.out.println("Working: " + this);

}

}

```

🔍 **Подвох:**

- Java `Proxy` работает **только с интерфейсами**

- Метод вызывается **дважды** — нужно быть осторожным с побочными эффектами

- Возврат значения только одного вызова (`original`) — важно, если метод что-то возвращает

🧠 **Чему учит задача:**

- Глубокому пониманию `java.lang.reflect.Proxy`

- Поведению `InvocationHandler` и сигнатур

- Умению комбинировать дизайн-паттерн **Proxy** и **Decorator**

- Практике метапрограммирования и логирования без изменения кода класса

---

@javarush