Sono d'accordo con @Zapadlo che questo non è un gran problema dato che le classi sono coese. In una configurazione più generale, però, potresti voler essere più flessibile con quel tipo di calcoli dipendenti.
In questo caso, puoi esaminare la composizione tradizionale delle funzioni per arrivare ad un'astrazione più generale:
Considera la tua prima classe B
( A
sembra iniziare la catena recuperando inizialmente i dati). Prende data
come input, diciamo di tipo T
. Fa alcuni effetti collaterali e calcola una nuova vista dei dati, chiamata data2
nel codice, di tipo S
. La stessa struttura è presente per C
. In termini di funzioni questo è fondamentalmente il Function<T, S>
composto con Function<S, U>
.
Normalmente, un Function
dovrebbe essere privo di effetti collaterali. In particolare, quando si entra nel regno della programmazione funzionale. A seconda dell'affinità tua e del tuo team con questo argomento, puoi semplicemente utilizzare un nome diverso per l'interfaccia sottostante. Supponiamo, un DataHandler<T,S>
che prende data
di tipo T
, ne fa qualcosa e restituisce alcuni dati aggiornati di tipo S
. È fondamentalmente la stessa cosa però. (Il nome DataHandler
non è però molto buono). D'altra parte, se hai familiarità con FP, puoi prendere la strada divertente e strappare le parti con effetti collaterali usando le monadi.
In ogni caso, l'astrazione della parte di gestione dati e di modifica nella propria interfaccia separata rimuove le dipendenze dirette tra queste classi. L'idea alla base di questa operazione è il principio di inversione delle dipendenze (DIP). Il codice chiamante risultante è quindi responsabile della composizione effettiva, quindi ci sarà un singolo posto dedicato nel codice che crea la catena di dipendenze B->C->D
, mentre le singole classi non sono infastidite da quella catena.
Inoltre, ci sono buone probabilità che dopo il refactoring basato sul DIP, scoprirai che il codice risultante che gestisce la trasformazione e l'inoltro dei dati a una dipendenza sembra molto simile o addirittura identico nelle diverse classi. Quindi puoi continuare a fare il refactoring seguendo il principio Non ripetere te stesso (ASCIUTTO) se ritieni che valga la pena.