In un ambiente in cui il refactoring è difficile l'estensibilità può essere un risparmiatore di vita. Tuttavia, questa non è una scusa per sovrascrivere il codice.
Dato che una catena di metodi del costruttore fluente e sottile è supportata da classi ben progettate che astraggono il lavoro dalla catena del metodo, c'è molto motivo per rendere estensibile il generatore fluente? Cioè, se la classe (i) implementa l'interfaccia (s) o estrae un'astrazione come nel getThis()
trucco . Con "thin" intendo al punto in cui ogni metodo di concatenamento ha solo una riga per eseguire il lavoro e una riga per restituire l'oggetto successivo nella catena.
Per favore considera entrambi autoreferenziale return this;
e step return new nextStep();
stili di catene di metodi.
Quando il lavoro è astratto, l'unica cosa rimasta per le classi della catena del metodo per definire realmente è il concatenamento (cioè l'insieme di metodi e ciò che restituiscono). Avere la (e) classe (i) del metodo concatenato implementa l'interfaccia (s) o usa il trucco getThis()
per usare le classi astratte sembra solo aggiungere più complessità senza alcun beneficio reale poiché non c'è lavoro per il livello astratto da fare e dal metodo concatenamento le classi sono tanto astratte quanto un'interfaccia.
Tuttavia, questo sembra essere vero solo quando la catena è in realtà sottile. Una volta che il vero lavoro si nasconde nella catena, inizia chiaramente a trarre beneficio dall'essere riutilizzabile.
Quindi sembra il modo migliore per "estendere" (aggiungere nuovi metodi / passaggi) queste sottili catene di metodi di generazione fluenti è solo pensare a un nuovo nome per la catena con cui iniziare, e scriverne una nuova da zero .
O mi manca qualcosa?
design uso di documenti e esempi
Un sottile ma molto semplice esempio di return new nextStep()
senza interfacce o il trucco getThis ().
Un esempio sottile ma meno semplice:
public class GotRequiredField {
public DidRequest doRequest() {
Request.do(requiredField);
return new DidRequest();
}
}
Potrebbe trattarsi di una classe nidificata o di una classe completa (se fornita di un nome migliore). Funziona in entrambi i modi quindi è solo una scelta organizzativa. La classe può essere estesa per cambiare ciò che doRequest () fa, ma Request.do () può anche essere cambiato senza toccare la catena del metodo.
Mi interessa la situazione in cui voglio aggiungere un metodo nuovo di zecca. Dite dopo aver pubblicato GotRequiredField voglio aggiungere un withlog opzionale (Log log) che restituisce questo a GotRequiredField.
Potrei estenderlo e inserire withLog () nella classe extendente. Ora devo cambiare ovunque GotRequiredField è instanciated (che per questo è solo un posto). Il trucco getThis può quindi essere utilizzato per garantire che anche i metodi non sovrascritti restituiscano l'istanza di implementazione di basso livello che ha il nuovo metodo.
Potrei anche provare a programmare un'interfaccia e fare un'iniezione di dipendenza, ma il nuovo metodo non può essere aggiunto alla vecchia interfaccia più della vecchia classe, quindi ora ho una nuova classe concreta che implementa due interfacce. Non vedo come l'implementazione di un'interfaccia mi aiuti qui. Riesco a vedere come usarli per fare l'iniezione di dipendenza per scambiare comportamenti, ma questo non ti dà nuovi metodi, solo un nuovo comportamento.
È il principio Aperto / Chiuso che sto sbattendo la testa contro qui. Quello che mi piacerebbe fare è entrare in GotRequiredField e aggiungere il nuovo metodo senza toccare nessuno degli altri metodi. Ma se la classe è "chiusa alle modifiche", non credo che sia autorizzato a farlo.
Sono disposto a fare il lavoro per "future proof" questa cosa ora (perché più tardi succhiarò) se posso essere sicuro di cosa sto comprando. Non sono sicuro di cosa sto comprando. Non voglio aggiungere nulla solo perché è stato bello.
Ad esempio: ho già scritto e testato interfacce annidate su classi nidificate per fare la catena del "prossimo passo". Funziona. Nasconde i tipi concreti. Ma le interfacce infastidiscono le persone che cercano di attraversare staticamente il codice (principalmente con ctrl-clic). E una catena completamente nuova non dovrebbe riutilizzare nessuna delle vecchie classi di concatenazione di catene poiché non c'è molto comportamento riutilizzabile (è sottile). Quindi non voglio aggiungere interfacce se non ho una buona spiegazione di ciò che ci stanno comprando.
Domande con problemi simili ma Non sono sicuro della risposta