Equivalente Java dei delegati Cocoa / protocolli informali Objective-C?
-
06-07-2019 - |
Domanda
Qual è l'equivalente Java dei delegati Cocoa?
(Capisco che posso avere un'interfaccia passata a una classe e che quella classe chiami i metodi appropriati, ma mi chiedo se c'è un altro modo per ottenere qualcosa di più vicino ai protocolli informali di Cocoa / Objective-C)
Soluzione
La risposta breve è che non c'è nulla in Java così vicino come vorresti, ma ci sono alternative. Il modello delegato non è difficile da implementare, non è altrettanto conveniente come farlo con Objective-C.
La ragione "protocolli informali" lavorare in Objective-C è perché il linguaggio supporta categorie , che ti consente di aggiungere metodi a classi esistenti senza sottoclassarli o addirittura avere accesso al codice sorgente. Pertanto, la maggior parte dei protocolli informali sono una categoria su NSObject. Ciò è chiaramente impossibile in Java.
Objective-C 2.0 opta per i metodi del protocollo @optional, che è un'astrazione molto più pulita e preferita per il nuovo codice, ma anche per avere un equivalente in Java.
Onestamente, l'approccio più flessibile è definire un protocollo delegato, quindi le classi implementano tutti i metodi. (Con IDE moderni come Eclipse, questo è banale.) Molte interfacce Java hanno una classe adattatrice di accompagnamento, e questo è un approccio comune per non richiedere all'utente di implementare molti metodi vuoti, ma limita l'eredità, il che rende la progettazione del codice poco flessibile . (Josh Bloch affronta questo problema nel suo libro "Efficace Java".) Il mio suggerimento sarebbe di fornire prima solo un'interfaccia, quindi aggiungere un adattatore se è veramente necessario.
Qualunque cosa tu faccia, evita di lanciare un UnsupportedOperationException
per " unimplemented " metodi. Ciò impone alla classe delegante di gestire le eccezioni per i metodi che dovrebbero essere facoltativi. L'approccio corretto è quello di implementare un metodo che non fa nulla, restituisce un valore predefinito, ecc. Questi valori dovrebbero essere ben documentati per i metodi che non hanno un tipo di ritorno vuoto.
Altri suggerimenti
Il miglior analogo a un protocollo informale che mi viene in mente è un'interfaccia che ha anche una classe di adattatori per consentire agli implementatori di evitare l'implementazione di ogni metodo.
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 */
}
}
}
Quindi qualcuno può venire e implementare semplicemente le cose che gli interessano:
class AwesomeDelegate extends MyClassDelegateAdapter {
@Override
public void didSomethingAwesome() {
System.out.println("Yeah!");
}
}
O quello, o pura riflessione che chiama "noto" metodi. Ma è pazzesco.
Non c'è nulla che ti impedisca di usare il modello delegato nei tuoi oggetti Java (non è solo un modello comunemente usato nel JDK come in Cocoa). Basta avere un ivar delegate
di un tipo conforme all'interfaccia whateverDelegate
, quindi nei metodi dell'istanza che si desidera delegare, inoltrare la chiamata del metodo sull'oggetto delegato se esiste . Probabilmente finiresti con qualcosa che assomiglia molto a this , tranne in Java invece di Obj-C.
Per quanto riguarda le interfacce opzionali, sarebbe più difficile. Suggerirei di dichiarare l'interfaccia, dichiarare una classe astratta che implementa metodi opzionali come metodi vuoti e quindi sottoclassare la classe astratta, sovrascrivendo i metodi opzionali che vuoi che questo particolare oggetto attui. C'è un limite potenzialmente grave qui a causa della mancanza di ereditarietà multipla in Java, ma è il più vicino possibile.