Principio di sostituzione di Liskov in pratica non ti consente di utilizzare eccessivamente l'ereditarietà dell'implementazione: non devi mai usare l'ereditarietà solo per il riutilizzo del codice (c'è una composizione per questo)! Aderendo a LSP, puoi essere certo che esiste effettivamente una "è-una relazione" tra la tua superclasse e la tua sottoclasse.
Ciò che dice è che le sottoclassi devono implementare tutti i metodi della sottoclasse in un modo simile all'implementazione dei metodi nella sottoclasse. Non si dovrebbe mai sovrascrivere un metodo con l'implementazione di NOP o restituire null quando il supertipo genera un'eccezione; indicato in termini Design by Contract, è necessario rispettare il contratto del metodo dalla superclasse quando si sostituisce un metodo. Un modo per difendersi contro la violazione di questo principio è non sovrascrivere un metodo implementato; invece estrai un'interfaccia e implementa quell'interfaccia in entrambe le classi.
Principio di segregazione dell'interfaccia , il principio di responsabilità singola e il principio di alta coesione di GRASP sono in qualche modo correlati; si riferiscono al fatto che un'entità dovrebbe essere responsabile di una sola cosa in modo che ci sia una sola ragione per il cambiamento in modo tale che il cambiamento avvenga molto facilmente.
In realtà dice che se una classe implementa un'interfaccia, allora deve implementare e usare tutti quei metodi dell'interfaccia. Se ci sono metodi che non sono necessari in quella particolare classe, allora l'interfaccia non è buona e deve essere divisa in due interfacce una che ha solo i metodi necessari per la classe originale. Può essere considerato da un POV, che si riferisce al principio precedente dal fatto che non ti permette di creare interfacce di grandi dimensioni in modo che la loro implementazione possa rompere LSP.
Puoi vedere Inversione dipendenza nel modello di fabbrica; qui sia il componente di alto livello (il client) che il componente di basso livello (l'istanza individuale da creare) dipendono da l'astrazione ( l'interfaccia).
Un modo per applicarlo in un'architettura a livelli: non è necessario definire un'interfaccia per un livello nel livello implementato ma nel modulo chiamato. Ad esempio, l'API al livello di origine dati non dovrebbe essere scritta nel livello sorgente dati ma nel livello logico aziendale, dove è necessario chiamarlo. In questo modo, lo strato di origine dati eredita / dipende dal comportamento definito nella logica di business (quindi l'inversione) e non viceversa (come sarebbe in un modo normale). Ciò fornisce flessibilità nella progettazione, lasciando funzionare la logica aziendale senza alcuna modifica del codice, con un'altra fonte di dati completamente diversa.