2009-06-18 21 views
6

Estaba leyendo Java 7 preview presentation (pdf) y había una diapositiva en Invocación encadenada. Aquí está el ejemplo utilizado en la diapositiva:Invocación encadenada en Java 7?

// Construction with setters 
DrinkBuilder margarita = new DrinkBuilder(); 
margarita.add("tequila"); 
margarita.add("orange liqueur"); 
margarita.add("lime juice"); 
margarita.withRocks(); 
margarita.withSalt(); 
Drink drink = margarita.drink(); 

// Construction with chained invocation 
Drink margarita = new DrinkBuilder() 
    .add("tequila") 
    .add("orange liqueur") 
    .add("lime juice") 
    .withRocks() 
    .withSalt() 
    .drink(); 

Y tengo sentimientos encontrados sobre esto. Uno no debe encadenar muchas invocaciones de métodos en una sola declaración. Por otro lado, escribir margarita.this() y margarita.that() tampoco es muy conveniente.

Ahora, vengo a Java del mundo Delphi. Y en Delphi está el constructo de lenguaje with. Esto es apreciado por unos pocos y aborrecido por muchos (¿o es al revés?). Encuentro que with es más elegante que la idea de invocación encadenada (que creo que funciona sobre la base del método void que devuelve referencia al objeto sobre el que se ha invocado, y esta es la parte que no me gusta, como debería regresar voidnada).

apreciaría la característica with idioma siendo adoptado por Java, por lo que el código de ejemplo se puede escribir así:

Drink margarita = null; 
with (new DrinkBuilder()) { 
    add("tequila"); 
    add("orange liqueur"); 
    add("lime juice"); 
    withRocks(); 
    withSalt(); 
    margarita = drink(); 
} 

¿Soy el único que prefieren esta solución a la invocación encadenado? ¿Alguien más siente que with podría ser una extensión útil para el lenguaje Java? (Me recuerda a la pregunta de alguien sobre la necesidad de "Java ++" ...)

+2

Esto no se limita a Java 7, puede escribir un constructor simplemente devolviendo "this" en los métodos. Un buen ejemplo es java.lang.StringBuilder. –

+5

Creo que el punto es que Java 7 permite el encadenamiento sin devolver esto, por lo tanto, cambiar la semántica de una llamada a un método. – OregonGhost

Respuesta

12

la con declaración se puede traducir en Java utilizando las clases anónimas con inicializador:

Drink margarita = new DrinkBuilder() {{ 
    add(“tequila”); 
    add(“orange liqueur”); 
    add(“lime juice”); 
    withRocks(); 
    withSalt(); 
}}.drink(); 

las desventajas de la utilización de este lenguaje están bien documentados here.

Invocación encadenada es un alias para Método de encadenamiento. Eso es bien conocido lenguaje y funciona con cualquier versión de Java:

class Chained { 

    public Chained withFoo() { 
     // ... 
     return this; 
    } 

    public Chained withBar() { 
     // ... 
     return this; 
    } 
}  

una propuesta de JDK 7 es allowing of chaining method also for void return type:

class ChainedJava7 { 

    public void withFoo() { 
     // ... 
    } 

    public void withBar() { 
     // ... 
    } 
}  
+1

Estaba escribiendo acerca de la inicialización del doble refuerzo cuando apareció su respuesta :-) –

+1

Esto es realmente bueno. +1 –

+2

Tenga en cuenta que la fecha límite para cambios de lenguaje pequeños a JDK7 pasó hace algunos meses. –

1

No me gusta este uso de with; Yo prefiero el Python with statement. Estoy de acuerdo con usted en que void debe significar void, sin embargo. En el ejemplo que proporcionas, si una persona realmente desea ser capaz de encadenar invocaciones de métodos, simplemente debería cambiar los tipos de devolución en sus métodos para que puedan encadenarse.

+0

Um, está vacío. Como productor, no le importa devolver nada, y a su consumidor no le importa recibir nada (aunque a veces lo hacen). ¿Por qué debería importarte? Semánticamente, nada cambia (excepto tener que escribir mucho). –

+0

Excepto que * * devuelve algo y lo está haciendo implícitamente. Si no devolvía nada, no podría invocar un método en él. Como esto es Java y casi todo lo demás es explícito, prefiero que el retorno sea explícito. –

2

This te puede interesar.

2

me gusta bastante with declaraciones de esa forma, pero yo prefiero la versión VB de ellos:

With testObject 
    .Height = 100 
    .Text = "Hello, World" 
    .ForeColor = System.Drawing.Color.Green 
End With 

Como cada atributo en el bloque With todavía tiene que ser precedido por un . sabe que you'r e haciendo referencia a una propiedad Object y no, por ejemplo, a una variable local, reduciendo cualquier colisión en el espacio de nombres.

Si tomamos el ejemplo:

with (new DrinkBuilder()) { 
    add(“tequila”); 
    add(“orange liqueur”); 
    add(“lime juice”); 
    withRocks(); 
    withSalt(); 
    margarita = drink(); 
} 

no hay manera fácil de saber si withSalt() es un método de DrinkBuilder o un método en la clase local. Si solo permite los métodos del objeto with -ed en el bloque with, entonces creo que se vuelven mucho menos útiles.

+0

Mi sugerencia sería withSalt() sería un método de Drink Builder. Si descubrió que la aplicación no está haciendo lo que debería, puede llamar a this.withSalt(); para que sea explícito lo que debe invocarse el método withSalt() del objeto. –

1

¿Quizás las muchas llamadas a un objeto son la señal de que es necesario mover un código?

+2

No, esto es parte de todo el mantra de Bean de Do One Thing porque Java no tiene propiedades de primera clase, así que tenemos que escribir getters y setters para todo. Es por eso. Algo más que se eliminó de Java 7 (propiedades). –

+0

@darthcoder - ¡me alegro de que lo hayas mencionado! No puedo entender por qué esto no ha sido parte de Java desde 1.0 –

1

Joshua Bloch en Effective Java El artículo n. ° 2 recomienda encarecidamente el uso de un generador cuando tiene un constructor con muchos argumentos. Una razón es que se puede escribir para garantizar que el objeto construido esté siempre en un estado consistente. También evita tener "constructores telescópicos" complejos en la clase del objeto construido. Otra más es que si desea que el objeto construido sea inmutable (p. Ej., Para la seguridad del hilo), no puede tener métodos setter.