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

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

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

Ответы

Ответ 1

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

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