Modelo anêmico e rico no contexto de modelos GRASP

Em uma edição recente do podcast DotNet & More, discutimos com Maxim Arshinov seu próximo relatório sobre o Moscou. Próximo "O brilho e a pobreza do modelo de sujeito". A posição de Maxim será facilmente acessível diretamente na conferência. Além disso, eu gostaria de considerar a visão do grande debate sobre os modelos de domínio Anemic VS "Rich" ("Rich") através do prisma dos modelos GRASP outrora populares


As discussões estão em andamento há muito tempo, por exemplo:



Antes de iniciar a análise, gostaria de esclarecer o assunto da disputa. A principal diferença entre o modelo anêmico e o rico é que ele não contém lógica de negócios no corpo da classe. Um exemplo bem conhecido do modelo anêmico pode ser o padrão DTO bem conhecido.


Um modelo "rico", por sua vez, pode conter lógica que descreve regras de negócios, funções etc. Observe que estamos considerando os métodos que refletem a lógica comercial. ToString, GetHashCode e outras partes "técnicas" das classes não estão incluídas no assunto da discussão e, portanto, são ignoradas.


GRASP


Conforme observado no início do artigo, consideraremos essa questão no contexto dos padrões GRASP . Esse conjunto de modelos foi apresentado no livro de Craig Larman “O uso de UML e padrões de design” e influenciou bastante a programação moderna, por exemplo, as regras de baixo acoplamento / alta coesão foram anunciadas no GRASP.


Para pessoas familiarizadas com os padrões GoF, esse conjunto de padrões pode parecer muito desfocado. O fato é que os padrões GRASP se concentram não na solução de problemas aplicados, mas na distribuição de responsabilidades por determinadas ações e operações entre objetos:


  • O criador é responsável por criar objetos.
  • O controlador é responsável pelas operações dos usuários
  • O indireto é responsável pela organização da malha fraca entre os objetos.
    E assim por diante

No contexto deste artigo, gostaria de focar nos seguintes padrões:


  • Especialista em informação
  • Fabricação pura

Especialista em informação


Problema: Qual é o princípio básico do compartilhamento de responsabilidades entre instalações?
Solução: Atribua esse dever a uma classe que tenha informações suficientes para realizá-lo.


Em outras palavras:


A responsabilidade deve ser atribuída àquele que possui o máximo de informações necessárias para a execução - o especialista em informações.

No contexto de C # : um método deve ser declarado na classe cujos campos e propriedades são usados ​​nesse método.
Por exemplo, se para calcular o valor da dívida todas as informações necessárias estão na essência do devedor (valor, hora do empréstimo), é nessa essência que o método apropriado deve ser anunciado.
Obviamente, essa simplificação é um tanto excessiva, mas o ponto principal deve ser claro.


Fabricação pura


Problema: Qual classe deve fornecer a implementação de Alta Coesão e Baixo Acoplamento se o modelo do Information Expert não fornecer uma solução adequada.
Solução: atribua um grupo de tarefas com alto grau de envolvimento a uma classe artificial que não represente um conceito específico da área de assunto.


Em outras palavras:


Se não for possível selecionar inequivocamente a entidade apropriada do modelo de assunto, à qual a responsabilidade pode ser atribuída, é necessário criar uma classe sintética que não exista na área de assunto.

No contexto de C # : se a implementação do método prevê o uso uniforme de várias entidades ou dependências externas, esse método deve ser declarado em uma classe separada. E essas classes são chamadas de serviços.
Por exemplo, para calcular o montante da dívida, você precisa conhecer não apenas os atributos do devedor, mas também os parâmetros do banco (taxa de juros, período de atraso permitido), vale a pena criar um serviço separado contendo o método apropriado.


E o que tudo isso significa?


No contexto do exposto, podemos distinguir um algoritmo bastante simples que ajuda a tomar uma decisão, colocar o método em um modelo ou em um serviço :


  • Se um método usar apenas propriedades do modelo, ele deverá ser declarado no modelo
  • Se um método usa, na maioria das vezes, as propriedades de um modelo e apenas parcialmente outro, ele pode ser declarado no modelo
  • Se o método usar uniformemente as propriedades de vários modelos, vale a pena movê-lo para um serviço separado ou existente
  • Se um método usa uma dependência externa, por exemplo, um Repositório, ele deve ser movido para um serviço separado ou existente


Sumário


Os padrões GRASP não podem ser vistos como a verdade suprema. Mas eles podem ajudar a entender facilmente a qual objeto atribuir esse ou aquele comportamento. Portanto, a disputa é anêmica ou o modelo “rico” pode não fazer sentido, uma vez que a decisão é tomada em cada caso, dependendo do modelo da área de assunto e do comportamento associado a ela. No processo de design do sistema, ambas as entidades com e sem comportamento aparecerão. E isso está correto.

Source: https://habr.com/ru/post/pt470021/


All Articles