2013-04-02 14 views
0

У меня есть класс, который реализует интерфейс. Есть еще один класс, который реализует этот интерфейс, и экземпляр этого второго класса поддерживает реализацию моего класса.Как уменьшить шаблон делегата?

Для многих методов, указанных интерфейсом, мой класс просто перенаправляет их прямо во второй класс.

public class MyClass implements MyInterface 
{ 
    private OtherClass otherClassInstance; // Also implements MyInterface. 
    // ... 
    void foo() { otherClassInstance.foo(); } 
    void bar() { otherClassInstance.bar(); } 
    void baz() { otherClassInstance.baz(); } 
    // ... 
} 

Просто получения моего класса со второго класса устранил бы все это, но это не имеет смысла, так как эти два класса не имеют никакого отношения друг к другу (помимо реализации общего интерфейса). Они представляют разные вещи - так получилось, что реализация моего класса копирует другой класс. Другими словами, мой класс реализуется поверх второго класса, но сам он не является подмножеством второго класса. Как известно, наследование предназначено для выражения отношения «есть-а», а не для совместного осуществления, поэтому в этом случае оно неуместно.

This часть беседы Джошуа Блоха хорошо иллюстрирует ситуацию.

Я знаю, что Java не поддерживает языковую поддержку для делегирования. Однако есть ли хоть какой-то способ очистить реализацию моего класса, чтобы он не был настолько избыточным?

+0

Lemme получите это прямое ... вы хотите расширить ArrayList, но не в каждом случае, а интерфейс не режет его ... Это ваш 'MyList' падает в основном в ArrayList, тогда это действительно имеет смысл для расширения ArrayList, и соответственно обрабатывать списки неарюристов. – Shark

+0

Обычно я проверяю причины «MyList». В большинстве случаев это ArrayList, и в некоторых случаях мне нужно особое поведение. Для этой ситуации я использую ArrayList и создаю Wrapper/Adapter/commands для обеспечения функциональности. И большую часть времени я смотрю на Гуаву и бесплатно получаю необходимые экстензии. –

+0

@Shark Нет, я не хочу расширять 'ArrayList'. Я делаю свой собственный класс для реализации 'List', а член' ArrayList' просто поддерживает мою реализацию. Это не означает, что объект 'MyList' будет использоваться вместо объекта ArrayList. – Maxpm

ответ

3

Ответ, который не является на самом деле ответ на актуальный вопрос:

Я бы сказал, жить с шаблонный. Пусть IDE генерирует его для вас. Пример: в Netbeans добавьте личное поле ArrayList, установите курсор туда, где вы хотите, чтобы методы отображались, нажмите alt-insert, выберите «Generate Methodate Method ...», выберите методы, которые вы хотите создать делегат потому что в диалоговом окне открывается, подает, просматривает сгенерированные методы и заставляет их поступать правильно, все готово.

Это немного уродливое, но по-прежнему предпочтительнее начинать беспорядок с отражением, когда вы имеете дело с одним классом, как будто это звучит. Ваш класс, вероятно, является классом, который вы закончите и полностью испытаете, а затем, надеюсь, никогда не трогайте его снова. Отражение создает затраты времени исполнения, которые не исчезают. В этом случае предпочтительнее использовать автоматически сгенерированный шаблон в исходном файле.

+0

Хороший вопрос о производительности. – Maxpm

+1

И отражение беспорядочно, подвержено ошибкам и взрывается во время выполнения. – Jazzepi

1

Первый способ использовать http://java.sun.com/javase/6/docs/api/java/lang/reflect/Proxy.html см обучающая http://docs.oracle.com/javase/1.4.2/docs/guide/reflection/proxy.html

Второй способ использования АОП вы можете создать диспетчеру, что перехватывать все вызов определенного класса

Для обоих способов вам нужно управлять обработкой методов с использованием Reflection API

EDITED TO SHOW IDEA Следующий код, взятый из учебника выше, немного изменился (см. Метод youListImpl.getRealArrayList() в методе вызова)

public class DebugProxy implements java.lang.reflect.InvocationHandler { 

    private YouListImpl youListImpl; 

    public static Object newInstance(Object obj) { 
    return java.lang.reflect.Proxy.newProxyInstance(
     obj.getClass().getClassLoader(), 
     obj.getClass().getInterfaces(), 
     new DebugProxy(obj)); 
    } 

    private DebugProxy(Object obj) { 
    this.obj = obj; 
    } 

    public Object invoke(Object proxy, Method m, Object[] args) 
    throws Throwable 
    { 
     Object result; 
    try { 
     System.out.println("before method " + m.getName()); 
     result = m.invoke(youListImpl.getRealArrayList(), args); 
     } catch (InvocationTargetException e) { 
     throw e.getTargetException(); 
     } catch (Exception e) { 
     throw new RuntimeException("unexpected invocation exception: " + 
         e.getMessage()); 
    } finally { 
     System.out.println("after method " + m.getName()); 
    } 
    return result; 
    } 
} 
+0

Не могли бы вы привести конкретные примеры того, как в этом случае можно использовать API отражения? – Maxpm

+0

@Maxpm просто поместите снимок – Dewfy

Смежные вопросы