A responsabilidade única (motivo da mudança) de uma entidade deve ser identificar-se de forma exclusiva, ou seja, sua responsabilidade deve ser identificável.
Livro DDD de Eric Evan, pág. 93:
A responsabilidade mais básica das Entidades é estabelecer continuidade para que o comportamento possa ser claro e previsível. Eles fazem isso melhor se forem mantidos livres. Em vez de focar nos atributos ou mesmo no comportamento, reduza a definição do objeto Entity às características mais intrínsecas, particularmente aquelas que o identificam ou são comumente usadas para encontrá-lo ou combiná-lo. Adicione apenas comportamentos essenciais ao conceito e aos atributos exigidos por esse comportamento.
Além disso, procure remover comportamentos e atributos em outros objetos associados à Entidade principal. Além dos problemas de identidade, as Entidades tendem a cumprir suas responsabilidades coordenando as operações dos objetos que possuem.
1
... reduza a definição do objeto ENTITY até as características mais intrínsecas, particularmente aquelas que o identificam ou são comumente usadas para encontrá-lo ou combiná-lo. Adicione apenas comportamentos essenciais ao conceito ...
Depois que uma entidade recebe um ID exclusivo , sua identidade é estabelecida e, portanto, eu presumo que essa entidade não precisa de nenhum comportamento para manter sua identidade ou ajudá-la a se identificar . Portanto, não entendo a que tipo de comportamento o autor se refere (além de find
e match
operações ) com " comportamento essencial ao conceito "?
2)
... reduza a definição do objeto ENTITY até as características mais intrínsecas, particularmente aquelas que o identificam ou são comumente usadas para encontrá-lo ou combiná-lo. ... Além disso, procure remover comportamentos e atributos em outros objetos associados à ENTITY principal.
Portanto, qualquer comportamento que não ajude a identificar a entidade, mas ainda assim caracterizá-lo como uma característica intrínseca dessa entidade (por exemplo, latir é intrínseco aos cães, voar é intrínseco aos aviões, pôr ovos é intrínseco aos pássaros .. .), deve ser colocado em outros objetos associados a essa entidade (exemplo: devemos colocar o comportamento de latido em um objeto associado a uma entidade de cachorro)?
3)
Além disso, procure remover comportamentos e atributos em outros objetos associados à ENTITY principal.
a) MyEntity
delega responsabilidades A_resp
e B_resp
objetos a
e b
, respectivamente.
Mesmo que a maioria dos A_resp
e B_resp
trabalho é feito por a
e b
casos, os clientes ainda são servidos A_resp
e B_resp
meio MyEntity
, o que significa que a partir da perspectiva do cliente as duas responsabilidades pertencem MyEntity
. Assim, isso não significa que MyEntity
também tem A_resp
e B_resp
responsabilidades e, como tal, está violando o SRP ?
b) Mesmo se assumirmos que A_resp
e B_resp
não pertencem a MyEntity
, MyEntity
ainda tem a responsabilidade AB_resp
de coordenar as operações de objetos a
e b
. Portanto, não MyEntity
viola o SRP, uma vez que, no mínimo, tem duas responsabilidades - identificar-se exclusivamente e também AB_resp
?
class MyEntity
{
private A a = ...
private B b = ...
public A GetA()
{ ... }
public B GetB()
{ ... }
/* coordinates operations of objects a and b */
public int AworkB()
{ ... }
}
/* A encapsulates a single responsibility resp_A*/
/* A is value object */
class A
{ ... }
/* B encapsulates a single responsibility resp_B*/
/* B is value object */
class B
{ ... }
ATUALIZAR:
1
O comportamento neste contexto refere-se ao comportamento semântico. Por exemplo, uma propriedade em uma classe (ou seja, atributo em um objeto de domínio) que é usada para identificar exclusivamente que ela possui um comportamento. Enquanto isso não é representado no código diretamente. O comportamento esperado é que não haverá valores duplicados para essa propriedade.
Portanto, no código, quase nunca precisaríamos realmente implementar um comportamento (ou seja, uma operação) que de alguma forma manteria a identidade da entidade, pois, como você explicou, esse comportamento só existe como um conceito em um modelo de domínio (na forma de um atributo de ID de uma entidade), mas quando convertemos esse atributo de ID em código, parte de sua semântica é perdida (ou seja, a parte que garante implicitamente que o valor do ID é único é perdida)?
2)
Além disso, uma propriedade como Age não tem contexto fora de uma Entidade da Pessoa e, como tal, não faz sentido mudar para um objeto diferente ... No entanto, essas informações podem ser facilmente armazenadas em um local separado pelo qual o identificador exclusivo, portanto, o referência confusa ao comportamento. A idade pode ser um valor carregado preguiçoso.
a) Se a Age
propriedade é carregada preguiçosamente, podemos chamá-la de comportamento, mesmo que semanticamente Age
seja apenas um atributo?
3)
Você poderia facilmente ter operações específicas para Endereço, como verificação de que é um endereço válido. Você pode não saber disso em tempo de design, mas todo esse conceito é dividir os objetos em suas menores partes
Embora eu concorde que perderíamos o contexto mudando Age
para um objeto diferente, o contexto não seria perdido se DateOfBirth
movermos a propriedade para um objeto diferente, mas geralmente não o movemos.
Qual é a principal razão pela qual nos mudaríamos Address
para outro objeto, mas não DateOfBirth
? Porque DateOfBirth
é mais intrínseco à Person
entidade ou porque há menos chances de que em algum lugar no futuro possamos precisar definir operações específicas DateOfBirth
?
4. Devo dizer que ainda não sei se MyEntity
também tem A_resp
e B_resp
responsabilidades e por que MyEntity
também AB_resp
não é considerado uma violação do SRP
EULERFX
1)
Os comportamentos aos quais o autor está se referindo são comportamentos associados à entidade. Esses são os comportamentos que modificam o estado da entidade
a) Se eu entendi direito, você está dizendo que a entidade deve conter apenas os comportamentos que modificam seus atributos (ou seja, seu estado )?
b) E quanto aos comportamentos que não necessariamente modificam o estado da entidade , mas ainda são considerados uma característica intrínseca dessa entidade (exemplo: latir seria uma característica intrínseca de uma Dog
entidade, mesmo que não modificasse Estado do cão )? Devemos incluir esses comportamentos em uma entidade ou devem ser movidos para outros objetos?
2)
Quanto a mudar o comportamento para outros objetos, o autor está se referindo especificamente a objetos de valor.
Embora minha citação não a inclua, o autor menciona no mesmo parágrafo que, em alguns casos, comportamentos (e atributos ) também serão transferidos para outras entidades (embora eu compreenda os benefícios de mudar comportamentos para VOs)
3) Supondo que MyEntity
(veja a pergunta 3. no meu post original) não viole o SRP, diríamos que uma responsabilidade de MyEntity
é, entre outras coisas, também composta por:
uma. A_resp
+ B_resp
+ AB_resp
( AB_resp
coordena objetos a
e b
)
ou
b. AB_resp
+ delegar A_resp
e B_resp
aos objetos ( a
e b
) associados a MyEntity
?
4) Livro DDD de Eric Evan, pág. 94:
Identificação do cliente é o único identificador da ENTIDADE do cliente (figura 5.5), mas o número e o endereço do telefone costumam ser usados para encontrar ou corresponder a um cliente. O nome não define a identidade de uma pessoa, mas é frequentemente usado como parte dos meios para determiná-la.
Neste exemplo, os atributos de telefone e endereço foram movidos para o Cliente, mas em um projeto real, essa escolha dependeria de como os clientes do domínio normalmente são correspondidos ou distinguidos. Por exemplo, se um Cliente tiver muitos números de telefone para diferentes finalidades, o número de telefone não está associado à identidade e deve permanecer no Contato de Vendas.
a)
Identificação do cliente é o único identificador da ENTIDADE do cliente (figura 5.5), mas o número e o endereço do telefone costumam ser usados para encontrar ou corresponder a um cliente. O nome não define a identidade de uma pessoa, mas é frequentemente usado como parte dos meios para determiná-la.
A citação afirma que apenas os atributos associados à identidade devem permanecer em uma entidade . Suponho que autor significa que a entidade deve conter apenas os atributos que costumam ser usados para encontrar ou corresponder a essa entidade , enquanto TODOS os outros atributos devem ser movidos?
b) Mas como / onde outros atributos devem ser movidos? Por exemplo (suposição aqui é que atributo de endereço não é usado para encontrar ou corresponder Customer
e, portanto, queremos mover atributo de endereço fora do Customer
):
se em vez de ter Customer.Address
(do tipo string
) criamos uma propriedade Customer.Address
do tipo Address
, movemos o atributo de endereço para um objeto VO associado (que é do tipo Address
) ou diríamos que Customer
ainda contém o atributo de endereço ?
c)
Neste exemplo, os atributos de telefone e endereço foram movidos para o Cliente, mas em um projeto real, essa escolha dependeria de como os clientes do domínio normalmente são correspondidos ou distinguidos. Por exemplo, se um Cliente tiver muitos números de telefone para diferentes finalidades, o número de telefone não está associado à identidade e deve permanecer no Contato de Vendas.
O autor não está errado aqui, já que se assumirmos cada um dos muitos números de telefone de contato que Customer
pertencem apenas a esse particular Customer
, eu diria que esses números de telefone estão associados à identidade tanto quanto quando Customer
apenas um número de telefone ?
5)
O motivo pelo qual o autor sugere descartar a entidade é que, quando alguém cria inicialmente uma entidade Cliente, há uma tendência a preenchê-la com qualquer atributo que se possa considerar associado a um cliente. Essa é uma abordagem centrada em dados que negligencia os comportamentos que levam a um modelo de domínio anêmico.
Off topic, mas eu pensei anêmicos modelo de domínio resultados de mover comportamento fora de uma entidade , enquanto que o seu exemplo é preencher uma entidade com muitos atributos , o que resultaria em Customer
ter muita comportamento (uma vez que provavelmente também incluir Customer
nos comportamentos que modificar esses atributos adicionais ) e, portanto, violar o SRP?
obrigado
Respostas:
O comportamento neste contexto refere-se ao comportamento semântico. Por exemplo, uma propriedade em uma classe (ou seja, atributo em um objeto de domínio) que é usada para identificar exclusivamente que ela possui um comportamento. Enquanto isso não é representado no código diretamente. O comportamento esperado é que não haverá valores duplicados para essa propriedade. Algo como um Endereço que pode ter sua própria identidade, mas não existe fora do contexto de uma Entidade Pessoa, ainda deve ser movido para seu próprio objeto. Assim, promovendo a Entidade em uma Raiz Agregada.
Além disso, uma propriedade como Age não tem contexto fora de uma Entidade Pessoa e, como tal, não faz sentido mudar para um objeto diferente. O contexto seria perdido e, portanto, você pode determinar com segurança que é um valor essencial para a Entidade da Pessoa. Não foi possível localizar o valor caso contrário. No entanto, essas informações podem ser facilmente armazenadas em um local separado do identificador exclusivo, daí a referência confusa ao comportamento . A idade pode ser um valor carregado preguiçoso.
Então, para responder sua pergunta. Não, não viola o Princípio da Responsabilidade Única. É lamentável afirmar que uma Pessoa deve ter apenas material de pessoa, e não algo como Endereço, que é mais complexo e relacionado a uma pessoa, deve existir como sua própria entidade.
Você poderia facilmente ter operações específicas para Endereço, como verificação de que é um endereço válido. Você pode não saber disso no momento do design, mas esse conceito é dividir os objetos em suas partes menores, para que algo assim seja relativamente simples quando feito após o fato.
Atualização: 1) Na maioria dos casos, essa validação de identidade é feita ao salvar um objeto em um armazenamento de dados. O que significa que o código que representa a validação da entidade existe, mas existe em outro lugar. Geralmente existe com o código responsável pela emissão do valor da identidade. É por isso que afirmo que a exclusividade não é representada diretamente no código da entidade.
2) A afirmação correta seria que
Age
é um atributo que possui comportamento. Você precisaria documentar o fato de que o Age é carregado preguiçosamente para que um desenvolvedor que consome essa propriedade possa tomar uma decisão precisa sobre como consumir essa propriedade3)
DateOfBirth
geralmente é um objeto diferente; Um objeto de data que já possui operações predefinidas. Em alguns idiomas, o objeto date já possui um modelo de domínio inteiro definido. Por exemplo, em c #, você pode especificar o fuso horário, se a data for UTC, adicionar e subtrair datas para obter um intervalo de tempo. Portanto, sua suposição sobre a mudançaDateOfBirth
seria correta.4) Se a única coisa que
MyEntity
faz é delegação e cooridação, então não, isso não viola o SRP. Sua única responsabilidade é delegar e coordenar e é referido como o padrão Facadefonte
Muito boa pergunta. O SRP não deve ser tomado tão literariamente. A identificação / pesquisa não é de responsabilidade da entidade no que diz respeito ao SRP. Outra pessoa é responsável por fornecer um ID (ou seja, a loja) e procurá-lo (ou seja, o Repositório ).
O objetivo principal de uma entidade é representar os conceitos descobertos pelo modelo. A única diferença entre uma Entidade e um Objeto de Valor é que a Entidade tem significado além de seus atributos não identificados. Por exemplo, se uma pessoa muda seu nome, ele ainda é a mesma pessoa, apenas com um nome diferente.
fonte
Se a identidade for estabelecida, sim, a entidade não precisa mais nada para ser identificado. Os comportamentos aos quais o autor está se referindo são comportamentos associados à entidade. Esses são os comportamentos que modificam o estado da entidade. Por exemplo, uma
Customer
entidade pode ter umMakePreferred
comportamento. O motivo pelo qual o autor sugere retirar a entidade é que, quando alguém cria umaCustomer
entidade inicialmente , existe uma tendência a preenchê-la com qualquer atributo que se possa pensar em estar associado a um cliente. Essa é uma abordagem centrada em dados que negligencia os comportamentos que levam a um modelo de domínio anêmico.Quanto a mudar o comportamento para outros objetos, o autor está se referindo especificamente a objetos de valor. A razão pela qual é uma boa ideia mudar o comportamento para os VOs é porque os VOs são geralmente "menores" do que as entidades, portanto, mais focados. Além disso, aspectos como imutabilidade e fechamento de operações simplificam o raciocínio sobre o código, além de torná-lo mais sólido .
Juntamente com os VOs, uma entidade serve como uma espécie de âncora que coordena os vários VOs que implementam seu comportamento.
Com relação ao SRP, sua confusão não é injustificada. Um problema com a implementação estereotipada de OOP de entidades é a fusão de identidade e estado. De fato, de uma perspectiva comportamental, a identidade não tem nada a ver com comportamentos. Em outras palavras, a identidade de uma entidade não é necessária para nenhum de seus comportamentos. Existem implementações em que essa confusão é eliminada, como o AggregateSource ou uma abordagem funcional que descrevo aqui .
O outro problema é que, até certo ponto, o SRP pode ser uma medida qualitativa. Qualquer pessoa pode apresentar uma definição de responsabilidade única que alguma classe viole. Pode-se dizer que a responsabilidade da entidade é implementar os comportamentos exigidos dessa entidade. Nesse sentido, ele tem uma única responsabilidade. Além disso, quando uma entidade delega comportamentos aos VOs constituintes, não está violando o SRP. O SRP não proíbe a composição do tipo. Ele alerta para reduzir o acoplamento entre os objetos a um mínimo absoluto, manter as interfaces o mais nítidas possível, etc.
ATUALIZAR
Sim, embora haja exceções ...
É aceitável que as entidades contenham métodos de fábrica para criar instâncias de entidades que sejam efetivamente entidades filhas, mas onde as referências a objetos não são usadas para travessia. Nesse caso, a entidade filha precisa ser persistida pelo serviço de aplicativo. O serviço de aplicativo usa a entidade pai para construir a entidade filho.
Você está encarando a responsabilidade da perspectiva da implementação. Em vez disso, considere a entidade como uma espécie de caixa preta com responsabilidades. O modo como ele lida com isso não é do seu interesse como alguém olhando de fora. O particionamento de responsabilidades entre VOs ou mesmo outras entidades é uma preocupação de implementação.
Mais especificamente, atributos que não são necessários para o comportamento nem procuram não devem fazer parte da entidade. Porque se importar? Além disso, com algo como o padrão de modelo de leitura , as entidades não precisam de nada além dos atributos exigidos para o comportamento.
Sim, com efeito, não há diferença entre um endereço de string ou um endereço de VO do endereço.
Eu não sou 100% na intenção do autor, mas acho que ele está apenas descrevendo como os requisitos de pesquisa de entidade podem alterar como a entidade e seus VOs correspondentes são estruturas.
Muitos atributos não significam muito comportamento. De fato, geralmente sugere o oposto. Muitos atributos com getters e setters, mas nenhum comportamento de encapsulamento.
fonte
TL; DR: você está pensando demais. No entanto, eu me diverti pensando demais junto com você. Então aperte o cinto ....
Não, isso não está certo. A responsabilidade única de uma entidade é a continuidade.
A identidade é uma conseqüência emergente da continuidade. Modelar a identidade como uma ideia separável é uma otimização de desempenho.
Aqui está um exemplo: o patrono de um restaurante dá o carro ao manobrista. Uma hora depois, um cliente do restaurante pede o carro. O manobrista deveria dar?
É fácil dizer que o manobrista deve entregar o carro se o cliente for o "mesmo". Mas o que isso realmente significa? A maneira correta de determinar isso é começar com o cliente "agora" e pesquisar para trás na história desse cliente para ver se a entrega do carro ao manobrista faz parte dessa história.
Na verdade, não podemos fazer isso, é claro. Temos problemas para rastrear nossa própria história com precisão, não importa a história de algo que não estava conosco o tempo todo. Então, em vez de usar a história do consumidor, tomamos atalhos. O usuário possui o canhoto do ticket que tem o mesmo número da tag atualmente vinculada às chaves? A carteira de motorista na carteira do usuário corresponde ao nome do título na DMV, a imagem na carteira de motorista se assemelha à face do usuário. Etc.
Em resumo: em vez de verificar o histórico do usuário, verificamos o estado atual do usuário, para ver se o estado atual é consistente com um histórico que abrange o período entre a chegada do carro e a solicitação de devolução.
Ao modelar entidades, usamos uma otimização análoga. Damos a todas as entidades as responsabilidades comuns de
Não estou descrevendo uma segunda responsabilidade da entidade aqui; a entidade ainda é responsável pela continuidade - certificando-se de que a história seja uma narrativa consistente. As responsabilidades do identificador são apenas um subconjunto que é comum a todas as entidades.
Ainda não temos nenhuma aplicação de exclusividade. Isso não é possível em uma única entidade, porque a exclusividade requer acesso ao estado de todas as entidades; onde uma única entidade só tem acesso próprio.
Mais uma vez, verificar todos os identificadores sempre não é prático; portanto, satisfazemos a exclusividade da maneira mais fácil: o código que gera o próximo identificador nunca deve se repetir.
No final, isso significa que podemos verificar a continuidade testando a equivalência de duas partes diferentes de estado na memória, poupando muito trabalho ao tentar consultar gráficos acíclicos.
Você também parece ter confundido o Princípio da Responsabilidade Única (que é realmente uma boa ideia) com um princípio de responsabilidade atômica. Decompor uma responsabilidade em partes menores e mais facilmente gerenciadas é compatível com o SRP.
fonte
Bem, depende de como você deseja vê-lo.
Outra maneira é: "O princípio de responsabilidade única está violando a entidade de domínio?"
Ambos são diretrizes. Não há "princípio" em nenhum lugar do design de software. No entanto, existem bons e maus designs. Ambos os conceitos podem ser usados de diferentes maneiras, para obter um bom design.
fonte