2009-07-30 3 views
13

Что такое Java-эквивалент делегатов Cocoa?Явный эквивалент делегатов какао/неофициальных протоколов Objective-C?

(Я понимаю, что у меня есть интерфейс, переданный классу, и этот класс вызывает соответствующие методы, но мне интересно, есть ли другой способ достичь чего-то более близкого к неофициальным протоколам Cocoa/Objective-C)

ответ

8

Короткий ответ: в Java нет ничего близкого, как хотелось бы, но есть альтернативы. Шаблон делегата выполнить не сложно, но это не так удобно, как с Objective-C.

Причина, по которой «неофициальные протоколы» работают в Objective-C, заключается в том, что язык поддерживает категории, что позволяет добавлять методы к существующим классам без их подклассификации или даже иметь доступ к исходному коду. Таким образом, большинство неофициальных протоколов являются категорией в NSObject. Это явно невозможно в Java.

Objective-C 2.0 выбирает методы @optional протокола, которые являются намного более чистой абстракцией и предпочитаются для нового кода, но даже от эквивалента в Java.

Честно говоря, наиболее гибким подходом является определение делегатского протокола, а затем классы реализуют все методы. (С современными IDE, такими как Eclipse, это тривиально.) Многие интерфейсы Java имеют сопутствующий класс адаптеров, и это общий подход, поскольку не требует от пользователя реализации множества пустых методов, но он ограничивает наследование, что делает дизайн кода негибким , (Джош Блох обращается к этому в своей книге «Эффективная Java».) Мое предложение состояло в том, чтобы сначала предоставить интерфейс, а затем добавить адаптер, если это действительно необходимо.

Независимо от того, что вы делаете, избегайте метаданных UnsupportedOperationException для «нереализованных» методов. Это заставляет делегирующий класс обрабатывать исключения для методов, которые должны быть необязательными. Правильный подход заключается в реализации метода, который ничего не делает, возвращает значение по умолчанию и т. Д. Эти значения должны быть хорошо документированы для методов, которые не имеют типа возврата void.

2

Нет ничего, что помешало бы вам использовать шаблон делегирования в ваших Java-объектах (это просто не обычный шаблон в JDK, как в Cocoa). Просто введите delegate ivar типа, который соответствует вашему интерфейсу WhateverDelegate, а затем в ваших методах экземпляра, которые вы хотите делегировать, переадресуйте вызов метода на объект делегата, если он существует. Вероятно, вы в конечном итоге получите что-то похожее на this, за исключением Java вместо Obj-C.

Что касается дополнительных интерфейсов, это будет сложнее. Я бы предложил объявить интерфейс, объявив абстрактный класс, который реализует необязательные методы как пустые методы, а затем подклассифицирует абстрактный класс, переопределяя необязательные методы, которые вы хотите реализовать для этого конкретного объекта. Здесь существует потенциально серьезное ограничение из-за отсутствия множественного наследования в Java, но это настолько близко, насколько я мог придумать.

+4

Throwing 'UnsupportedOperationException' - страшная идея! API никогда не должны заставлять пользователей иметь дело с исключениями в обычных шаблонах использования, только для исключительного потока. Шаблон делегирования в Cocoa является надежным в том, что он молча пропускает нереализованные методы делегата. –

+0

Очень хорошая точка. Я забыл, как раздражают исключения Java. –

+0

@Quinn Taylor: однако, это то, что «факультативные» протоколы * были выполнены во многих частях библиотеки Java. Например, интерфейс «Коллекция» указывает, что такие методы, как add() и remove(), являются «необязательными операциями», которые вызывают UnsupportedOperationException, если они не поддерживают его. – newacct

5

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

public class MyClass { 

    private MyClassDelegate delegate; 

    public MyClass() { 

    } 

    // do interesting stuff 

    void setDelegate(MyClassDelegate delegate) { 
     this.delegate = delegate; 
    } 

    interface MyClassDelegate { 
     void aboutToDoSomethingAwesome(); 
     void didSomethingAwesome(); 
    } 

    class MyClassDelegateAdapter implements MyClassDelegate { 

     @Override 
     public void aboutToDoSomethingAwesome() { 
      /* do nothing */ 
     } 

     @Override 
     public void didSomethingAwesome() { 
      /* do nothing */ 
     } 
    } 
} 

Тогда кто-то может прийти и просто реализовать вещи, о которых они заботятся:

class AwesomeDelegate extends MyClassDelegateAdapter { 

    @Override 
    public void didSomethingAwesome() { 
     System.out.println("Yeah!"); 
    } 
} 

Либо так, либо чистое отражение вызова «известные» метода. Но это безумие.

+0

Но, как всегда, подход адаптера искусственно ограничивает наследование. В Java нет дополнительных методов интерфейса, таких как Obj-C, в протоколах, поэтому вы не получите то же самое. Самый чистый (но все же раздражающий) подход заключается в реализации пустых методов. –

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