2009-07-30 10 views

Respuesta

8

La respuesta corta es que no hay nada en Java lo más cerca que quisieras, pero hay alternativas. El patrón de delegado no es difícil de implementar, simplemente no es tan conveniente como hacerlo con Objective-C.

La razón por la cual los "protocolos informales" funcionan en Objective-C es porque el lenguaje admite categorías, que le permiten agregar métodos a clases existentes sin crear subclases, o incluso tener acceso al código fuente. Por lo tanto, la mayoría de los protocolos informales son una categoría en NSObject. Esto es claramente imposible en Java.

Objective-C 2.0 opta por los métodos de protocolo @optional, que es una abstracción mucho más limpia y preferida para el nuevo código, pero aún más lejos de tener un equivalente en Java.

Honestamente, el enfoque más flexible es definir un protocolo delegado, luego las clases implementan todos los métodos. (Con IDEs modernos como Eclipse, esto es trivial.) Muchas interfaces Java tienen una clase de adaptador acompañante, y este es un enfoque común para no requerir que el usuario implemente muchos métodos vacíos, pero restringe la herencia, lo que hace que el diseño del código sea inflexible . (Josh Bloch aborda esto en su libro "Effective Java"). Mi sugerencia sería que solo proporcione primero una interfaz, luego agregue un adaptador si es realmente necesario.

Hagas lo que hagas, evita arrojar un UnsupportedOperationException por métodos "no implementados". Esto fuerza a la clase delegante a manejar excepciones para métodos que deberían ser opcionales. El enfoque correcto es implementar un método que no hace nada, devuelve un valor predeterminado, etc. Estos valores deben estar bien documentados para los métodos que no tienen un tipo de retorno nulo.

2

No hay nada que te impida usar el patrón delegado en tus objetos Java (no es un patrón comúnmente utilizado en el JDK como en Cocoa). Solo tiene un delegate ivar de un tipo que se ajuste a su interfaz WhateverDelegate, luego, en los métodos de instancia que desee delegar, reenvíe la llamada al método al objeto delegado, si existe. Probablemente termines con algo que se parece mucho a this, excepto en Java en lugar de Obj-C.

En lo que respecta a las interfaces opcionales, eso sería más difícil. Sugeriría que se declare la interfaz, se declare una clase abstracta que implemente métodos opcionales como métodos vacíos, y luego se subclasifique la clase abstracta, anulando los métodos opcionales que se desea que implemente este objeto en particular. Aquí existe una limitación potencialmente grave debido a la falta de herencia múltiple en Java, pero eso es lo más cercano que se me ocurrió.

+4

Lanzar 'UnsupportedOperationException' es una idea terrible! Las API nunca deben obligar a los usuarios a tratar con excepciones en los patrones de uso normales, solo para un flujo excepcional. El patrón delegado en Cocoa es robusto porque pasa silenciosamente sobre los métodos delegados no implementados. –

+0

Muy buen punto. Había olvidado lo molestas que son las excepciones de Java. –

+0

@Quinn Taylor: sin embargo, así es como se han realizado * protocolos * opcionales en muchas partes de la biblioteca de Java. Por ejemplo, la interfaz "Colección" especifica que los métodos como add() y remove() son "operaciones opcionales", que arrojan UnsupportedOperationException si no lo admiten. – newacct

5

El mejor protocolo analógico para un protocolo informal en el que puedo pensar es una interfaz que también tiene una clase de adaptador para permitir a los implementadores evitar la implementación de todos los métodos.

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

Entonces alguien puede venir y simplemente poner en práctica las cosas que les importa:

class AwesomeDelegate extends MyClassDelegateAdapter { 

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

O eso, o que llama la reflexión pura "conocido" métodos. Pero eso es una locura

+0

Pero como siempre, el enfoque del adaptador restringe artificialmente la herencia. Java no tiene métodos de interfaz opcionales como Obj-C en los protocolos, por lo que no obtendrá exactamente lo mismo. El enfoque más limpio (aunque molesto) es implementar métodos vacíos. –