2009-06-18 20 views
6

Stavo leggendo un Java 7 preview presentation (pdf) e c'era una diapositiva su Invocazione concatenata. Ecco l'esempio utilizzato nella diapositiva:Invocazione concatenata in 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(); 

E ho sentimenti contrastanti su questo. Non si dovrebbero concatenare troppe chiamate di metodo in un'unica istruzione. D'altra parte, scrivere margarita.this() e margarita.that() non è neanche troppo conveniente.

Ora, vengo a Java dal mondo di Delfi. E in Delphi c'è il costrutto del linguaggio with. Questo è caro a pochi e odiato da molti (o è il contrario?). Trovo che with sia più elegante dell'idea di invocazione concatenata (che credo funzioni sulla base del metodo void che restituisce il riferimento all'oggetto su cui è stato richiamato - e questa è la parte che non mi piace, come void dovrebbe restituire niente).

Gradirei la funzione with lingua che viene adottato da Java, in modo che il codice di esempio potrebbe essere scritto in questo modo:

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

sono io l'unico che preferirebbe questa soluzione per l'invocazione incatenato? Qualcun altro ritiene che with potrebbe essere un'estensione utile per il linguaggio Java? (Mi ricorda la domanda di qualcuno sulla necessità di "Java ++" ...)

+2

Questo non è limitato a Java 7, è possibile scrivere un builder semplicemente restituendo "questo" nei metodi. Un buon esempio è java.lang.StringBuilder. –

+5

Penso che il punto sia che Java 7 consente il concatenamento senza restituirlo, modificando quindi la semantica di una chiamata di metodo. – OregonGhost

risposta

12

la con dichiarazione può essere tradotto in Java utilizzando le classi anonime con inizializzatore:

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

gli aspetti negativi di utilizzare questo linguaggio sono ben documentati here.

Invocazione concatenata è un alias per il concatenamento del metodo. Che è ben noto linguaggio e funziona con qualsiasi versione di Java:

class Chained { 

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

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

una proposta di JDK 7 è allowing of chaining method also for void return type:

class ChainedJava7 { 

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

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

Stavo scrivendo dell'inizializzazione della doppia parentesi quando è apparsa la tua risposta :-) –

+1

Questo è davvero bello. +1 –

+2

Nota, la scadenza per le modifiche della lingua piccola a JDK7 è passata alcuni mesi fa. –

1

Non sono un fan di questo uso di with; Preferisco di gran lunga lo Python with statement. Sono d'accordo con te che void dovrebbe significare void, però. Nell'esempio che fornisci, se una persona vuole davvero essere in grado di concatenare le invocazioni dei metodi, dovrebbe semplicemente cambiare i tipi di ritorno sui loro metodi in modo da renderli concatenabili.

+0

Um, è vuoto. Come produttore non ti interessa restituire nulla, e al tuo consumatore non importa ricevere nulla (anche se a volte lo fanno). Perché dovrebbe interessarti? Semanticamente, nulla cambia (tranne dover scrivere così tanto). –

+0

Tranne che * stai * restituendo qualcosa, e lo stai facendo implicitamente. Se non si restituisce nulla, non è possibile richiamare un metodo su di esso. Dato che questo è Java e praticamente tutto il resto è esplicito, preferirei che il rendimento fosse esplicito. –

2

This potrebbe interessarti.

2

mi piace molto with dichiarazioni di quella forma, ma io preferisco la versione VB di loro:

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

Come ogni attributo nel blocco With deve ancora essere preceduto da un . si sa che you'r e fa riferimento a una proprietà Object e non, diciamo, a una variabile locale, riducendo qualsiasi collisione nello spazio dei nomi.

Se prendiamo il tuo esempio:

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

non c'è un modo facile dire se withSalt() è un metodo di DrinkBuilder o di un metodo nella classe locale. Se si accettano solo metodi dell'oggetto with nel blocco with, penso che diventino molto meno utili.

+0

Il mio suggerimento sarebbe withSalt() sarebbe un metodo del Drink Builder. Se hai trovato che l'applicazione non sta facendo ciò che dovrebbe, puoi chiamare this.withSalt(); per rendere esplicito quale metodo withSalt() dell'oggetto deve essere invocato. –

1

Forse le molte chiamate a un oggetto sono il segno che alcuni codici devono essere spostati?

+2

No, questo fa parte dell'intero mantello Bean di Do One Thing perché Java non ha proprietà di prima classe, quindi dobbiamo scrivere getter e setter per tutto. Ecco perchè. Qualcos'altro che è stato rilasciato da Java 7 (proprietà). –

+0

@darthcoder - lieto che l'abbiate detto! Non riesco a capire perché questo non è stato parte di Java dal 1.0 –

1

Joshua Bloch in Effective Java L'articolo n. 2 consiglia vivamente l'uso di un generatore quando si dispone di un costruttore con molti argomenti. Una ragione è che può essere scritta per garantire che l'oggetto costruito sia sempre in uno stato coerente. Evita anche di avere complessi "costruttori telescopici" nella classe dell'oggetto costruito. Un'altra ancora è che se si desidera che l'oggetto costruito sia immutabile (ad esempio, per la sicurezza dei thread), non può avere metodi di setter.