Digamos que temos uma lista de entidades de tarefas e um ProjectTask
subtipo. As tarefas podem ser fechadas a qualquer momento, exceto as ProjectTasks
que não podem ser fechadas uma vez que tenham o status Iniciado. A interface do usuário deve garantir que a opção de fechar uma inicialização ProjectTask
nunca esteja disponível, mas algumas salvaguardas estão presentes no domínio:
public class Task
{
public Status Status { get; set; }
public virtual void Close()
{
Status = Status.Closed;
}
}
public class ProjectTask : Task
{
public override void Close()
{
if (Status == Status.Started)
throw new Exception("Cannot close a started Project Task");
base.Close();
}
}
Agora, ao chamar Close()
uma tarefa, há uma chance de a chamada falhar se for ProjectTask
com o status iniciado, quando não seria se fosse uma tarefa base. Mas esses são os requisitos de negócios. Deveria falhar. Isso pode ser considerado uma violação do princípio da substituição de Liskov ?
public Status Status { get; private set; }
:; caso contrário, o Close()
método pode ser contornado.
Task
não introduzam incompatibilidades bizarras no código polimórfico, que apenas conhece, Task
é importante. O LSP não é um capricho, mas foi introduzido precisamente para ajudar na manutenção de grandes sistemas.
TaskCloser
processo que closesAllTasks(tasks)
. Obviamente, esse processo não tenta capturar exceções; afinal, não faz parte do contrato explícito de Task.Close()
. Agora você apresenta ProjectTask
e de repente TaskCloser
começa a lançar exceções (possivelmente não tratadas). Este é um grande negócio!