2011-12-20 7 views
6

Estoy conteniendo el "objeto primario" (con la mayoría de las características) dentro de un "objeto auxiliar" que proporcionará métodos de conveniencia. Solo tengo una interfaz disponible, aparte de un objeto devuelto con esa interfaz de un método de fábrica. Estoy pensando que una buena manera de "extender" este objeto es la composición, pero el problema es que mi superclase debe implementar la interfaz del objeto primario, que sería aproximadamente 600 líneas de código de código auxiliar.¿Cuál es la forma más corta de delegar métodos no implementados en un objeto contenido en Java?

Claramente, una solución sencilla pero detallada sería completar todos los resguardos para que simplemente llamen a los métodos del objeto primario. ¿Hay una mejor manera que esto en Java? En otros idiomas con los que estoy familiarizado, habría formas de hacer delegación automática para métodos que no están implementados en el objeto auxiliar.

Ejemplo:

 
class Helper implements Interface { 
    Primary primary; 

    Helper(Primary _primary) { 
     primary = _primary; 
    } 

    void helper() { 
     doStuff(); 
    } 

    // 500 lines of this 
    void stub() { 
     primary.stub(); 
    } 
} 

Nota:

plan original era sólo tiene que utilizar expresiones regulares para reemplazar todos los TODOs ramal en Eclipse con las llamadas reales. Sin embargo, buscaré una herramienta Eclipse que lo haga automáticamente. Además, parece que la extensión de la interfaz o el uso de Proxy es mejor al final, por lo que perseguiremos eso.

+2

Eclipse puede hacer esto por usted. Haga clic derecho -> Fuente -> Generar métodos delegados. –

Respuesta

3

Hay algunos possiblites.


Primero: Usar una implementación abstracta que los delegados las llamadas.

abstract class InterfaceDelegator implements Interface { 
    protected final Interface primary; 
    public InterfaceDelegator() { 
    this.primary = primary; 
    } 
    // implements all the calls as: primary.call(...) 
} 

class Helper extends InterfaceDelegator { 
    // override just the methods you need 
} 

Segundo: Usar el proxy (probablemente más limpia).

Ver: http://docs.oracle.com/javase/1.5.0/docs/guide/reflection/proxy.html

final Interface primary = ...; 
return (Interface) Proxy.newProxyInstance(Inteface.class.getClassLoader(), 
    new Class[] { Interface.class }, 
    new InvocationHandler() { 
    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { 
     // if m is a method that you want to change the behaviour of, return something 
     // by default, delegate to the primary 
     return m.invoke(primary, args); 
    } 
    }); 

El manejador de invocación se encargará de las llamadas a través de la ejecución de un método que ha codificado, una todos los demás se delegaría a la aplicación principal. Luego, puede ajustar un código como este en un método u otra fábrica.


Tercero: Usando el IDE para generar los métodos (como otros señalaron).

12

Use Lombok's @Delegate annotation.

El segundo más rápido es usar su IDE; muchos tienen esta funcionalidad.

El tercero más rápido es escribir un pequeño introspector pequeño y volcarlo usted mismo.

+0

Estoy interesado en su solución introspecter. ¿Me puede dar algunos consejos sobre cómo implementarlo? –

+0

+1 para el enlace de Lombok :) –

+0

Desafortunadamente, el equipo de lombok ya no recomienda el uso de @Delegate. Planean eliminar de lanzamientos futuros. –

1

Algunos IDEs admiten la herencia a la refactorización de delegaciones. Esto generará la mayor parte del código que necesita.

Si no desea utilizar esto, puede crear un proxy dinámico para dirigir las llamadas de método a una selección de delegados implementadores.

1

Hay dos opciones de las cuales puede elegir una sola: verbosidad reducida o velocidad/rendimiento. Por supuesto, puede utilizar un enfoque genérico basado en la reflexión que podría afectar el rendimiento en el tiempo de ejecución o ir con los métodos autogenerados de Lombok/eclipse y vivir con la verbosidad/magia. :)

0

Su interfaz es demasiado grande. Las clases e interfaces tienden a crecer con el tiempo, y suele ser mucho más problemático que su valor romperlas. Sin embargo, una vez que comienzas a envolver una gran clase dentro de otra, es posible que haya que hacer algo de limpieza.

En términos simples, lo que quiere hacer es romper la interfaz en piezas manejables. La interfaz original pierde un montón de métodos, pero recoge algunos para devolver objetos que implementan otras interfaces. Ahora, en lugar de container.getX();, tendría

Interface container = new Helper(primary); 
Letter li = container.getLetterInterface(); // Convenience Method 
              // "li" comes straight from primary 
int x = li.getX(); 

Idealmente Interface gotas de más de 100 métodos para menores de 20 años El regresó implementaciones de interfaz pueden ser los objetos primarios subyacentes, u objetos creados por ellos. (Y en este último caso, según lo deseen, pueden mostrar los datos a partir del momento en que se llamó al método o los valores actuales en primary). Esto básicamente le permite deslizar información directamente desde primary a la persona que llama sin molestarse con los métodos de conveniencia .

Haga esto bien y su código será un lote más fácil de administrar en esta y otras situaciones. Pero es mucho trabajo, por lo que si sabe esto, lo último que va a hacer con este código, use una de las otras soluciones.

Cuestiones relacionadas