Questo potrebbe o meno essere una violazione dell'LSP.
Scherzi a parte. Ascoltami.
Se segui l'LSP, gli oggetti di tipo ProjectTask
devono comportarsi come si comportano gli oggetti di tipo Task
.
Il problema con il tuo codice è che non hai documentato come si comportano gli oggetti di tipo Task
. Hai scritto codice, ma non contratti. Aggiungerò un contratto per Task.Close
. A seconda del contratto che aggiungo, il codice per ProjectTask.Close
fa o non segue l'LSP.
Dato il seguente contratto per Task.Close, il codice per ProjectTask.Close
non segue l'LSP:
// Behaviour: Moves the task to the closed state
// and does not throw any Exception.
// Default behaviour: Moves the task to the closed state
// and does not throw any Exception.
public virtual void Close()
{
Status = Status.Closed;
}
Dato il seguente contratto per Task.Close, il codice per ProjectTask.Close
fa segue l'LSP:
// Behaviour: Moves the task to the closed status if possible.
// If this is not possible, this method throws an Exception
// and leaves the status unchanged.
// Default behaviour: Moves the task to the closed state
// and does not throw any Exception.
public virtual void Close()
{
Status = Status.Closed;
}
I metodi che possono essere sovrascritti devono essere documentati in due modi:
-
Il "comportamento" documenta ciò che può essere invocato da un client che sa che l'oggetto destinatario è un Task
, ma non sa quale classe sia un'istanza diretta di. Indica anche ai progettisti di sottoclassi le cui sostituzioni sono ragionevoli e che non sono ragionevoli.
-
Il "comportamento predefinito" documenta ciò che può essere invocato da un client che sa che l'oggetto destinatario è un'istanza diretta di Task
(cioè ciò che ottieni se usi new Task()
. di sottoclassi quale comportamento verrà ereditato se non sovrascrive il metodo.
Ora le seguenti relazioni dovrebbero contenere:
- Se S è un sottotipo di T, il comportamento documentato di S dovrebbe affinare il comportamento documentato di T.
- Se S è un sottotipo di (o uguale a) T, il comportamento del codice di S dovrebbe affinare il comportamento documentato di T.
- Se S è un sottotipo di (o uguale a) T, il comportamento predefinito di S dovrebbe affinare il comportamento documentato di T.
- Il comportamento effettivo del codice per una classe dovrebbe perfezionare il suo comportamento predefinito documentato.