Do domínio anêmico ao domínio dirigido
-
21-12-2019 - |
Pergunta
Eu estava tentando encontrar um exemplo claro e simples do que realmente significa um domínio anêmico.Há muita teoria por aí e também muitas perguntas bem respondidas.Ainda assim, não consegui ter uma ideia clara sobre até que ponto o significado de “domínio anêmico” realmente vai.Portanto, acredito que seria mais simples ver um exemplo prático fictício de um design de domínio anêmico e perguntar como isso poderia evoluir para um design orientado por domínio ...
Então, digamos que temos uma entidade de dados do tipo Dados da Tarefa:
public class TaskData
{
public Guid InternalId { get; set; }
public string Title { get; set; }
public string Details { get; set; }
public TaskState ExplicitState { get; set; }
public IEnumerable<TaskData> InnerTasks { get; set; }
}
E há a necessidade de uma propriedade adicional chamada "Estado atual", que é um estado computado:se a Tarefa tiver subtarefas internas, o valor depende estritamente dos filhos, caso contrário, o "Estado atual" é igual a "Estado Explícito"
Se eu escrever esta lógica em separado serviço classe (eu os chamo de "motores") Nós temos:
internal class TaskStateCalculator
{
public TaskState GetState(TaskData taskData)
{
if (taskData.InnerTasks.Any())
{
if (taskData.InnerTasks.All(x => this.GetState(x) == TaskState.Done))
{
return TaskState.Done;
}
if (taskData.InnerTasks.Any(x => this.GetState(x) == TaskState.InProgress))
{
return TaskState.InProgress;
}
return TaskState.Default;
}
return taskData.ExplicitState;
}
}
O primeira pergunta é:
O código acima reflete um design de domínio anêmico, mesmo que o Calculadora TaskState serviço/mecanismo faz parte da minha camada de domínio?Se sim, para evitá-lo, precisaremos mover a lógica dentro do Dados da Tarefa classe (e renomear Dados da Tarefa para Tarefa).Estou certo?
O segunda questão é (na verdade, uma cadeia deles):
E se tivermos uma situação mais difícil?Digamos que haja a necessidade de uma propriedade chamada ComputeAlgo dentro Tarefa entidade, e a lógica desta propriedade precisa acessar toda a tarefa repositório.Neste caso, o Tarefa classe teria uma dependência de Repositório de Tarefas.Isso estaria bem?Como a EF construiria uma instância dessa classe?Qual é a alternativa?
Solução
Eu estava tentando encontrar um exemplo claro e simples do que realmente significa um domínio anêmico
Na verdade, é muito fácil passar de um modelo de domínio anêmico para um modelo rico.
- Defina todos os configuradores de propriedades como
private
e, em seguida, adicione métodos se desejar alterar o estado de um modelo. - Avalie tudo Lei de Deméter violações e adicionar métodos quando adequado.
Eventualmente você terá um modelo correto.
No seu caso, eu encapsularia essa lógica dentro TaskData
já que sua TaskStateCalculator viola a Lei de Demeter
public class TaskData
{
public Guid InternalId { get; private set; }
public string Title { get; private set; }
public string Details { get; private set; }
public TaskState ExplicitState { get; private set; }
public IEnumerable<TaskData> InnerTasks { get; private set; }
public TaskState GetState()
{
if (!InnerTasks.Any())
return ExplicitState;
if (InnerTasks.All(x => this.GetState(x) == TaskState.Done))
{
return TaskState.Done;
}
if (InnerTasks.Any(x => this.GetState(x) == TaskState.InProgress))
{
return TaskState.InProgress;
}
return TaskState.Default;
}
}
outra coisa é que eu provavelmente não exporia a coleção InnerTasks ao mundo exterior (apenas a teria como um campo de membro).Mas é difícil dizer porque não sei como a classe é usada em outros cenários.
Por que setters privados
Cada vez que você precisa alterar mais de uma propriedade, geralmente é melhor descrever o comportamento com um método, pois é impossível esquecer de alterar todas as propriedades necessárias.Um método também descreve melhor o que você está tentando fazer do que alterar um conjunto de propriedades.
Mesmo se você alterar apenas uma única propriedade, essa propriedade poderá definir a classe em um estado inválido, pois a alteração pode não ser compatível com o restante das informações da classe.Não se esqueça que o encapsulamento é um dos princípios fundamentais da OOP