Java equivalent of Cocoa delegates / Objective-C i

2019-03-09 23:49发布

What is the Java equivalent of Cocoa delegates?

(I understand that I can have an interface passed to a class, and have that class call the appropriate methods, but I'm wondering if there is any other way to achieve something closer to Cocoa/Objective-C's informal protocols)

3条回答
劫难
2楼-- · 2019-03-10 00:09

The short answer is there's nothing in Java as close as you'd like, but there are alternatives. The delegate pattern isn't hard to implement, it's just not quite as convenient as doing it with Objective-C.

The reason "informal protocols" work in Objective-C is because the language supports categories, which allow you to add methods to existing classes without subclassing them, or even having access to the source code. Thus, most informal protocols are a category on NSObject. This is clearly impossible in Java.

Objective-C 2.0 opts for @optional protocol methods, which is a much cleaner abstraction and preferred for new code, but even further from having an equivalent in Java.

Honestly, the most flexible approach is to define a delegate protocol, then have classes implement all the methods. (With modern IDEs like Eclipse, this is trivial.) Many Java interfaces have an accompanying adapter class, and this is a common approach for not requiring the user to implement a lot of empty methods, but it restricts inheritance, which makes code design inflexible. (Josh Bloch addresses this in his book "Effective Java".) My suggestion would be to only provide an interface first, then add an adapter if it's truly necessary.

Whatever you do, avoid throwing an UnsupportedOperationException for "unimplemented" methods. This forces the delegating class to handle exceptions for methods that should be optional. The correct approach is to implement a method that does nothing, returns a default value, etc. These values should be well documented for methods that don't have a void return type.

查看更多
乱世女痞
3楼-- · 2019-03-10 00:15

There's nothing stopping you from using the delegate pattern in your Java objects (It's just not a commonly used pattern in the JDK like it is in Cocoa). Just have a delegate ivar of a type that conforms to your WhateverDelegate interface, then in your instance methods that you want delegated, forward the method call onto the delegate object if it exists. You would probably end up with something that looks a lot like this, except in Java instead of Obj-C.

As far as optional interfaces go, that would be more difficult. I would suggest declaring the interface, declaring an abstract class that implements optional methods as empty methods, and then subclassing the abstract class, overriding the optional methods that you want this particular object to implement. There's a potentially severe limitation here due to the lack of multiple inheritance in Java, but that's as close as I could come up with.

查看更多
手持菜刀,她持情操
4楼-- · 2019-03-10 00:18

Best analog to an informal protocol I can think of is an interface that also has an adapter class to allow implementers to avoid implementing every method.

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 */
        }
    }
}

Then someone can come along and just implement the stuff they care about:

class AwesomeDelegate extends MyClassDelegateAdapter {

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

Either that, or pure reflection calling "known" methods. But that's insane.

查看更多
登录 后发表回答