Sim, é uma violação do LSP. O princípio de substituição de Liskov requer que
- As pré-condições não podem ser fortalecidas em um subtipo.
- As pós-condições não podem ser enfraquecidas em um subtipo.
- As invariantes do supertipo devem ser preservadas em um subtipo.
- Restrição de histórico (a "regra do histórico"). Os objetos são considerados modificáveis somente através de seus métodos (encapsulamento). Como os subtipos podem introduzir métodos que não estão presentes no supertipo, a introdução desses métodos pode permitir mudanças de estado no subtipo que não são permissíveis no supertipo. A restrição de histórico proíbe isso.
Seu exemplo quebra o primeiro requisito reforçando uma condição prévia para chamar o método Close()
.
Você pode consertar isso trazendo a pré-condição reforçada para o nível superior da hierarquia de herança:
public class Task {
public Status Status { get; set; }
public virtual bool CanClose() {
return true;
}
public virtual void Close() {
Status = Status.Closed;
}
}
Estipulando que uma chamada de Close()
é válida somente no estado em que CanClose()
retorna true
, você faz com que a pré-condição se aplique ao Task
, bem como ao ProjectTask
, corrigindo o LSP violação:
public class ProjectTask : Task {
public override bool CanClose() {
return Status != Status.Started;
}
public override void Close() {
if (Status == Status.Started)
throw new Exception("Cannot close a started Project Task");
base.Close();
}
}