Java-эквивалент делегатов Какао / Неофициальные протоколы Objective-C? - PullRequest
13 голосов
/ 31 июля 2009

Что такое Java-эквивалент делегатов Какао?

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

Ответы [ 3 ]

8 голосов
/ 31 июля 2009

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

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

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

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

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

5 голосов
/ 31 июля 2009

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

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!");
    }
}

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

2 голосов
/ 31 июля 2009

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

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

...