Vediamo questo praticamente
Obj 3
ora sa che Obj 4
esiste. E allora? Perché ci importa?
Dice DIP
"I moduli di alto livello non dovrebbero dipendere da moduli di basso livello. Entrambi dovrebbero dipendere da astrazioni."
OK ma non sono tutte le astrazioni degli oggetti?
DIP dice anche
"Le astrazioni non dovrebbero dipendere dai dettagli. I dettagli dovrebbero dipendere dalle astrazioni."
OK ma, se il mio oggetto è incapsulato correttamente, non nasconde alcun dettaglio?
Ad alcune persone piace insistere ciecamente sul fatto che ogni oggetto necessita di un'interfaccia per parole chiave. Non sono uno di loro. Mi piace insistere ciecamente sul fatto che se non li userai ora hai bisogno di un piano per affrontare il bisogno di qualcosa di simile in seguito.
Se il tuo codice è completamente refactable in ogni versione, puoi estrarre le interfacce in seguito se ne hai bisogno. Se hai pubblicato un codice che non vuoi ricompilare e ti ritrovi a desiderare di parlare attraverso un'interfaccia, avrai bisogno di un piano.
Obj 3
sa che Obj 4
esiste. Ma Obj 3
sa se Obj 4
è concreto?
Questo è il motivo per cui è così bello NON diffondersi new
ovunque. Se Obj 3
non sa se Obj 4
è concreto, probabilmente perché non lo ha creato, allora se ti intrufolassi più tardi e ti trasformassi Obj 4
in una classe astratta Obj 3
, non ti importerebbe.
Se riesci a farlo, allora Obj 4
è stato completamente astratto per tutto il tempo. L'unica cosa che ti fa ottenere un'interfaccia tra loro dall'inizio è la certezza che qualcuno non aggiungerà accidentalmente codice che regala che Obj 4
è concreto in questo momento. I costruttori protetti possono mitigare questo rischio ma ciò porta a un'altra domanda:
Obj 3 e Obj 4 sono nello stesso pacchetto?
Gli oggetti sono spesso raggruppati in qualche modo (pacchetto, spazio dei nomi, ecc.). Quando raggruppati con saggezza, cambia gli impatti più probabili all'interno di un gruppo piuttosto che tra i gruppi.
Mi piace raggruppare per funzione. Se Obj 3
e Obj 4
fanno parte dello stesso gruppo e dello stesso livello, è molto improbabile che tu ne abbia pubblicato uno e non voglialo rifattorizzare mentre devi cambiare solo l'altro. Ciò significa che è meno probabile che questi oggetti traggano beneficio dall'aver messo un'astrazione tra di loro prima che abbia un chiaro bisogno.
Se stai attraversando un confine di gruppo, è davvero una buona idea lasciare che gli oggetti su entrambi i lati possano variare indipendentemente.
Dovrebbe essere così semplice ma sfortunatamente sia Java che C # hanno fatto scelte sfortunate che complicano questo.
In C # è tradizione nominare ogni interfaccia di parole chiave con un I
prefisso. Ciò costringe i clienti a SAPERE che stanno parlando con un'interfaccia di parole chiave. Ciò è in disordine con il piano di refactoring.
In Java è tradizione utilizzare un modello di denominazione migliore: FooImple implements Foo
tuttavia, ciò aiuta solo a livello di codice sorgente poiché Java compila le interfacce delle parole chiave in un binario diverso. Ciò significa che quando si Foo
esegue il refactoring da client concreti a astratti che non necessitano di un singolo carattere di codice modificato, è comunque necessario ricompilarli.
Sono questi BUG in questi particolari linguaggi che impediscono alle persone di rimandare l'astrattismo formale fino a quando non ne hanno davvero bisogno. Non hai detto quale lingua stai usando, ma hai capito che ci sono alcune lingue che semplicemente non hanno questi problemi.
Non hai detto quale lingua stai usando, quindi ti esorto ad analizzare attentamente la tua lingua e la tua situazione prima di decidere che saranno interfacce di parole chiave ovunque.
Il principio YAGNI svolge qui un ruolo chiave. Ma anche "Per favore, rendimi difficile spararmi al piede".