Non puoi decidere se un codice viola l'LSP dal codice stesso. Devi conoscere il contratto che ciascun metodo deve soddisfare.
Nell'esempio, c'è nessun contratto esplicito dato , quindi dobbiamo indovinare quale potrebbe essere il contratto previsto del metodo Close()
.
Osservando l'implementazione della classe base del metodo te Close (), l'unico effetto di tale metodo è che dopo il Status
è Status.Closed
. La mia ipotesi migliore di un contratto per questo metodo è la seguente:
Do whatever is necessary to make the Status
become Status.Closed
.
Ma questa è solo una ipotesi plausibile . Nessuno può esserne sicuro se non è scritto esplicitamente.
Diamo per scontato la mia ipotesi.
Anche il metodo Close()
sottoposto a override soddisfa quel contratto ? Ci sono due possibilità che dopo aver eseguito questo metodo abbiamo Status.Closed
:
- Abbiamo già avuto
Status.Closed
prima di chiamare il metodo.
- Abbiamo avuto
Status.Started
. Quindi chiamiamo l'implementazione di base, impostando il campo su Status.Closed
.
- In tutti gli altri casi ci ritroviamo con uno stato diverso.
Se Status
ha solo i due possibili valori Closed
e Started
(es. enum a 2 valori), tutto va bene, non c'è violazione LSP, perché otteniamo sempre Status.Closed
dopo Close()
metodo.
Ma probabilmente ci sono più possibili valori di Status
, che finiscono con un Status
non essendo Status.Closed
, quindi che violano il contratto .
L'OP ha chiesto la famosa frase "ovunque io usi la classe base, la sua classe derivata può essere usata".
Quindi mi piacerebbe approfondire.
L'ho letto come "ovunque io usi la classe base nel suo contratto , la sua classe derivata può essere utilizzata, senza violare quel contratto .
Quindi non si tratta solo di non produrre errori di compilazione o di eseguire senza errori di lancio, si tratta di eseguire ciò che il contratto richiede .
E si applica solo alle situazioni in cui chiedo alla classe di fare qualcosa che rientra nel suo range di operazioni previsto. Quindi non dobbiamo preoccuparci delle situazioni di abuso (ad esempio laddove non sono soddisfatte le condizioni preliminari).
Dopo aver riletto la tua domanda, penso che dovrei aggiungere un paragrafo sul polimorfismo in quel contesto.
Il polimorfismo indica che per istanze di classi diverse, la stessa chiamata al metodo determina l'esecuzione di diverse implementazioni. Pertanto, il tecnoforisma consente tecnicamente di sostituire il nostro metodo Close()
con uno che invece ad es. apre un flusso. Tecnicamente, è possibile, ma è un cattivo uso del polimorfismo. E un principio sugli usi buoni e cattivi del polimorfismo è l'LSP.