La responsabilidad única (razón para cambiar) de una entidad debe ser identificarse de manera única, en otras palabras, su responsabilidad debe ser localizable.
El libro DDD de Eric Evan, pág. 93:
La responsabilidad más básica de las entidades es establecer la continuidad para que el comportamiento pueda ser claro y predecible. Lo hacen mejor si se mantienen libres. En lugar de enfocarse en los atributos o incluso en el comportamiento, elimine la definición del objeto Entity hasta las características más intrínsecas, particularmente aquellas que lo identifican o se usan comúnmente para encontrarlo o combinarlo. Agregue solo el comportamiento que sea esencial para el concepto y los atributos que requiere ese comportamiento.
Más allá de eso, busque eliminar el comportamiento y los atributos en otros objetos asociados con la Entidad central. Más allá de los problemas de identidad, las Entidades tienden a cumplir con sus responsabilidades coordinando las operaciones de los objetos que poseen.
1)
... elimine la definición del objeto ENTITY hasta las características más intrínsecas, particularmente aquellas que lo identifican o se usan comúnmente para encontrarlo o combinarlo. Agregue solo un comportamiento que sea esencial para el concepto ...
Una vez que a una entidad se le asigna una identificación única , se establece su identidad y, por lo tanto, supongo que dicha entidad no necesita ningún comportamiento para mantener su identidad o ayudarla a identificarse . Por lo tanto, no entiendo qué tipo de comportamiento es el autor se refiere a (además find
y match
operaciones ) con " el comportamiento que es esencial para el concepto "?
2)
... elimine la definición del objeto ENTITY hasta las características más intrínsecas, particularmente aquellas que lo identifican o se usan comúnmente para encontrarlo o combinarlo. ... Más allá de eso, busca eliminar el comportamiento y los atributos en otros objetos asociados con la ENTIDAD central.
Entonces, cualquier comportamiento que no ayude a identificar la entidad, pero aún así caracterizaríamos ese comportamiento como una característica intrínseca de esa entidad (es decir, el ladrido es intrínseco a los perros, volar es intrínseco a los aviones, poner huevos es intrínseco a las aves ... .), debe colocarse en otros objetos asociados con esa entidad (ejemplo: debemos poner el comportamiento de ladrar en un objeto asociado con una entidad de perro)?
3)
Más allá de eso, busque eliminar el comportamiento y los atributos en otros objetos asociados con la ENTIDAD central.
a) MyEntity
delega responsabilidades A_resp
y B_resp
objetos a
y b
, respectivamente.
A pesar de que la mayor parte de A_resp
y B_resp
trabajo es realizado por a
y b
casos, los clientes están siendo servidos A_resp
y B_resp
a través de MyEntity
, lo que significa que desde la perspectiva del cliente las dos responsabilidades pertenecen a MyEntity
. Por lo tanto, no significa eso MyEntity
también tiene A_resp
y B_resp
responsabilidades y, como tal, está violando SRP ?
b) Incluso si asumimos eso A_resp
y B_resp
no pertenecemos MyEntity
, MyEntity
todavía tiene la responsabilidad AB_resp
de coordinar las operaciones de los objetos a
y b
. Entonces, ¿no MyEntity
viola SRP ya que como mínimo tiene dos responsabilidades : identificarse de manera única y también 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
{ ... }
ACTUALIZAR:
1)
El comportamiento en este contexto se refiere al comportamiento semántico. Por ejemplo, una propiedad en una clase (es decir, un atributo en un objeto de dominio) que se usa para identificarla de forma exclusiva tiene un comportamiento. Si bien esto no está representado en el código directamente. El comportamiento esperado es que no habrá valores duplicados para esa propiedad.
Entonces, en el código, casi nunca necesitaríamos implementar realmente un comportamiento (es decir, una operación) que de alguna manera mantendría la identidad de la entidad, ya que como usted explicó, dicho comportamiento solo existe como un concepto en un modelo de dominio (en forma de un atributo ID de una entidad), pero cuando traducimos este atributo de ID en código, se pierde parte de su semántica (es decir, se pierde la parte que implícitamente se asegura de que el valor de ID sea único).
2)
Además, una propiedad como Age no tiene contexto fuera de una Entidad Persona y, como tal, no tiene sentido moverse a un objeto diferente ... Sin embargo, esa información podría almacenarse fácilmente en una ubicación separada que el identificador único, de ahí el referencia confusa al comportamiento. La edad podría ser un valor cargado flojo.
a) Si la Age
propiedad está cargada de manera diferida, ¿podemos llamarlo un comportamiento, aunque semánticamente Age
sea solo un atributo?
3)
Fácilmente podría tener operaciones específicas de Dirección, como la verificación de que es una dirección válida. Puede que no lo sepas en el momento del diseño, pero todo este concepto es descomponer los objetos en sus partes más pequeñas.
Si bien estoy de acuerdo en que perderíamos el contexto al movernos Age
a un objeto diferente, el contexto no se perdería si moviéramos la DateOfBirth
propiedad a un objeto diferente, pero generalmente no lo movemos.
¿Cuál es la razón principal por la que nos moveríamos Address
a otro objeto, pero no DateOfBirth
? ¿Porque DateOfBirth
es más intrínseco a la Person
entidad o porque hay menos posibilidades de que en algún momento en el futuro necesitemos definir operaciones específicas para DateOfBirth
?
4. debo decir que todavía no sé si MyEntity
también tiene A_resp
y B_resp
responsabilidades y por eso MyEntity
también haber AB_resp
no se considera una violación de SRP
EULERFX
1)
Los comportamientos a los que se refiere el autor son comportamientos asociados con la entidad. Estos son los comportamientos que modifican el estado de la entidad.
a) Si te entiendo correctamente, ¿estás diciendo que la entidad solo debe contener esos comportamientos que modifican sus atributos (es decir, su estado )?
b) ¿Y qué hay de los comportamientos que no necesariamente modifican el estado de la entidad , pero que aún se consideran como una característica intrínseca de esa entidad (ejemplo: ladrar sería una característica intrínseca de una Dog
entidad, incluso si no se modificara) Estado del perro )? ¿Deberíamos incluir estos comportamientos en una entidad o deberían trasladarse a otros objetos?
2)
En cuanto al comportamiento de movimiento a otros objetos, el autor se refiere específicamente a objetos de valor.
Aunque mi cita no lo incluye, pero el autor menciona en el mismo párrafo que en algunos casos los comportamientos (y los atributos ) también se trasladarán a otras entidades (aunque entiendo los beneficios de trasladar los comportamientos a las VO)
3) Suponiendo que MyEntity
(vea la pregunta 3. en mi publicación original) no viola SRP, diríamos que una responsabilidad de MyEntity
entre otras cosas también comprende:
a. A_resp
+ B_resp
+ AB_resp
( AB_resp
coordina objetos a
y b
)
o
si. AB_resp
+ delegar A_resp
y B_resp
a objetos ( a
y b
) asociados con MyEntity
?
4) El libro DDD de Eric Evan, pág. 94:
CustomerID es el único identificador de la ENTIDAD del cliente (figura 5.5), pero el número de teléfono y la dirección a menudo se utilizan para encontrar o hacer coincidir un Cliente. El nombre no define la identidad de una persona, pero a menudo se usa como parte de los medios para determinarlo.
En este ejemplo, los atributos del teléfono y la dirección se trasladaron al Cliente, pero en un proyecto real, esa elección dependería de cómo los clientes del dominio suelen coincidir o distinguirse. Por ejemplo, si un cliente tiene muchos números de teléfono de contacto para diferentes propósitos, entonces el número de teléfono no está asociado con la identidad y debe permanecer con el contacto de ventas.
un)
CustomerID es el único identificador de la ENTIDAD del cliente (figura 5.5), pero el número de teléfono y la dirección a menudo se utilizan para encontrar o hacer coincidir un Cliente. El nombre no define la identidad de una persona, pero a menudo se usa como parte de los medios para determinarlo.
La cita establece que solo los atributos asociados con la identidad deben permanecer en una entidad . Supongo que autor significa que la entidad debe contener solo aquellos atributos que a menudo se usan para encontrar o coincidir con esta entidad , mientras que TODOS los demás atributos deben moverse.
b) ¿Pero cómo / dónde se deben mover otros atributos ? Por ejemplo (se supone que el atributo de dirección no se usa para buscar o coincidir Customer
y, por lo tanto, queremos mover el atributo de dirección fuera de Customer
):
si en lugar de tener Customer.Address
(de tipo string
) creamos una propiedad Customer.Address
de tipo Address
, ¿movimos el atributo de dirección a un objeto VO asociado (que es de tipo Address
) o diríamos que Customer
todavía contiene el atributo de dirección ?
C)
En este ejemplo, los atributos del teléfono y la dirección se trasladaron al Cliente, pero en un proyecto real, esa elección dependería de cómo los clientes del dominio suelen coincidir o distinguirse. Por ejemplo, si un cliente tiene muchos números de teléfono de contacto para diferentes propósitos, entonces el número de teléfono no está asociado con la identidad y debe permanecer con el contacto de ventas.
El autor no está equivocado aquí, ya que si asumimos cada uno de los muchos números de teléfono de contacto que Customer
solo pertenecen a ese particular Customer
, entonces diría que estos números de teléfono están asociados con la identidad tanto como cuando Customer
solo tenía un número de teléfono ?
5)
La razón por la que el autor sugiere desmantelar la entidad es que cuando uno crea inicialmente una entidad de Cliente, existe la tendencia de llenarla con cualquier atributo que se pueda pensar que está asociado con un cliente. Este es un enfoque centrado en los datos que pasa por alto los comportamientos que finalmente conducen a un modelo de dominio anémico.
Fuera de tema, pero pensé que el modelo de dominio anémico resulta de mover el comportamiento fuera de una entidad , mientras que su ejemplo es poblar una entidad con muchos atributos , lo que resultaría en Customer
un comportamiento excesivo (ya que probablemente también incluiríamos en Customer
los comportamientos que modificar estos atributos adicionales ) y por lo tanto en violación de SRP?
Gracias
Respuestas:
El comportamiento en este contexto se refiere al comportamiento semántico. Por ejemplo, una propiedad en una clase (es decir, un atributo en un objeto de dominio) que se usa para identificarla de forma exclusiva tiene un comportamiento. Si bien esto no está representado en el código directamente. El comportamiento esperado es que no habrá valores duplicados para esa propiedad. Algo como una Dirección que puede tener su propia identidad, pero que no existe fuera del contexto de una Entidad Persona, aún debe trasladarse a su propio objeto. Promoviendo así la Entidad en una Raíz Agregada.
Además, una propiedad como Age no tiene contexto fuera de una Entidad Persona y, como tal, no tiene sentido moverse a un objeto diferente. El contexto se perdería y, por lo tanto, puede determinar con seguridad que es un valor esencial para la Entidad Persona. No podría localizar el valor de lo contrario. Sin embargo, esa información podría almacenarse fácilmente en una ubicación separada del identificador único, de ahí la referencia confusa al comportamiento . La edad podría ser un valor cargado flojo.
Entonces para responder a tu pregunta. No, no viola el principio de responsabilidad única. Es simple decir que una Persona debe tener solo cosas de persona, y no algo como Dirección, que es más complejo y relacionado con una persona, debe existir como su propia entidad.
Fácilmente podría tener operaciones específicas de Dirección, como la verificación de que es una dirección válida. Puede que no lo sepas en el momento del diseño, pero todo este concepto consiste en descomponer los objetos en sus partes más pequeñas para que algo como esto sea relativamente simple cuando se hace después del hecho.
Actualización: 1) En la mayoría de los casos, esta validación de identidad se realiza al guardar un objeto en un almacén de datos. Lo que significa que el código que representa la validación de la entidad existe, pero existe en otro lugar. Por lo general, existe con el código responsable de emitir el valor de identidad. Es por eso que afirmo que la unicidad no está representada directamente en el código de la entidad.
2) La declaración correcta sería que
Age
es un atributo que tiene comportamiento. Debería documentar el hecho de que Age tiene una carga lenta para que un desarrollador que consuma esa propiedad pueda tomar una decisión precisa sobre cómo consumir esa propiedad3)
DateOfBirth
generalmente es un objeto diferente; Un objeto de fecha que ya tiene operaciones predefinidas en él. En algunos idiomas, el objeto de fecha ya tiene un modelo de dominio completo definido en él. Por ejemplo, en c # puede especificar la zona horaria, si la fecha es UTC, sume y reste fechas para obtener un intervalo de tiempo. Por lo tanto, su suposición sobre el movimientoDateOfBirth
sería correcta.4) Si lo único que
MyEntity
hace es delegación y cooridinación, entonces no, no viola SRP. Su única responsabilidad es delegar y coordinar y se conoce como el patrón Fachada.fuente
Muy buena pregunta El SRP no debe tomarse tan literalmente. La identificación / búsqueda no es responsabilidad de la entidad en lo que respecta al SRP. Alguien más es responsable de darle una identificación (es decir, la tienda) y de buscarlo (es decir, el repositorio ).
El propósito principal de una entidad es representar los conceptos descubiertos por el modelo. La única diferencia entre una entidad y un objeto de valor es que la entidad tiene un significado más allá de sus atributos no identificativos. Por ejemplo, si una persona cambia su nombre, sigue siendo la misma persona, solo que con un nombre diferente.
fuente
Si se establece la identidad, entonces sí, la entidad no necesita nada más para ser identificada. Los comportamientos a los que se refiere el autor son comportamientos asociados con la entidad. Estos son los comportamientos que modifican el estado de la entidad. Por ejemplo, una
Customer
entidad puede tener unMakePreferred
comportamiento. La razón por la que el autor sugiere desmantelar la entidad es que cuando uno crea inicialmente unaCustomer
entidad, existe la tendencia de poblarla con cualquier atributo que se pueda pensar que está asociado con un cliente. Este es un enfoque centrado en datos que pasa por alto los comportamientos que finalmente conducen a un modelo de dominio anémico.En cuanto al comportamiento de movimiento a otros objetos, el autor se refiere específicamente a objetos de valor. La razón por la que es una buena idea trasladar el comportamiento a las VO es porque las VO suelen ser "más pequeñas" que las entidades, por lo tanto, más enfocadas. Además, aspectos como la inmutabilidad y el cierre de operaciones simplifican el razonamiento sobre el código y lo hacen más SÓLIDO .
Junto con los VO, una entidad sirve como una especie de ancla que coordina los diversos VO que implementan su comportamiento.
Con respecto a SRP, su confusión no es injustificada. Un problema con la implementación estereotipada de OOP de entidades es la fusión de identidad y estado. De hecho, desde una perspectiva conductual, la identidad no tiene nada que ver con los comportamientos. En otras palabras, la identidad de una entidad no se requiere para ninguno de sus comportamientos. Hay implementaciones en las que se elimina esta combinación, como AggregateSource o un enfoque funcional que describo aquí .
El otro problema es que, hasta cierto punto, el SRP puede ser una medida cualitativa. Cualquiera puede llegar a una definición de responsabilidad única que viola alguna clase. Se puede decir que la responsabilidad de la entidad es implementar los comportamientos requeridos de esa entidad. En ese sentido, tiene una sola responsabilidad. Además, cuando una entidad delega comportamientos a VO constituyentes, no está violando SRP. SRP no prohíbe la composición de este tipo. Se advierte a uno para reducir el acoplamiento entre objetos a un mínimo absoluto, mantener las interfaces lo más desnudas posible, etc.
ACTUALIZAR
Sí, aunque hay excepciones ...
Es aceptable que las entidades contengan métodos de fábrica para crear instancias de entidades que serían efectivamente entidades secundarias, pero donde las referencias a objetos no se usan para el recorrido. En este caso, el servicio de aplicación debe persistir a la entidad secundaria. El servicio de aplicación utiliza la entidad principal para construir la entidad secundaria.
Estás mirando la responsabilidad desde la perspectiva de implementación. En cambio, considere la entidad como una especie de caja negra con responsabilidades. Cómo maneja eso no es de su interés como alguien que mira desde afuera. La división de responsabilidades entre VO o incluso otras entidades es una preocupación de implementación.
Más específicamente, los atributos que no son necesarios para el comportamiento ni para buscar no deberían ser parte de la entidad. ¿Por qué molestarse? Además, con algo como el patrón de modelo de lectura , las entidades no necesitan nada más que los atributos necesarios para el comportamiento.
Sí, en efecto, no hay diferencia entre una dirección de cadena o una dirección Address VO.
No estoy 100% en la intención del autor, pero creo que solo está describiendo cómo los requisitos de búsqueda de la entidad pueden alterar cómo la entidad y sus VO correspondientes son estructuras.
Muchos atributos no implican mucho comportamiento. De hecho, generalmente sugiere lo contrario. Muchos atributos con captadores y establecedores, pero sin comportamiento de encapsulación.
fuente
TL; DR: has terminado de pensar esto. Sin embargo, me divertí pensando demasiado contigo. Así que abróchate el cinturón ...
No, eso no está bien. La responsabilidad única de una entidad es la continuidad.
La identidad es una consecuencia emergente de la continuidad. Modelar la identidad como una idea separable es una optimización del rendimiento.
Aquí hay un ejemplo: un cliente del restaurante le da un auto al valet. Una hora después, un patrón del restaurante pregunta por el auto. ¿Debería darlo el valet?
Es fácil decir que el valet debería darle el auto si el patrón es el "mismo". Pero, ¿qué significa esto realmente? La manera correcta de determinar eso es comenzar con el patrón "ahora" y buscar hacia atrás a través de la historia de ese patrón para ver si la entrega del auto al valet es parte de esa historia.
En realidad no podemos hacer eso, por supuesto. Tenemos problemas para rastrear nuestra propia historia con precisión, no importa la historia de algo que no estuvo con nosotros todo el tiempo. Entonces, en lugar de usar la historia del patrón, tomamos atajos. ¿El usuario posee el talón de boleto que tiene el mismo número que la etiqueta actualmente atada a las llaves? ¿La licencia de conducir en la billetera del usuario coincide con el nombre del título en el DMV, la imagen de la licencia de conducir se parece a la cara del usuario? Etc.
En resumen: en lugar de verificar el historial del usuario, verificamos el estado actual del usuario para ver si el estado actual es consistente con un historial que abarca el período entre la llegada del automóvil y la solicitud de devolución.
Cuando modelamos entidades, usamos una optimización análoga. Otorgamos a todas las entidades las responsabilidades comunes de
No estoy describiendo una segunda responsabilidad de la entidad aquí; la entidad sigue siendo responsable de la continuidad, asegurándose de que la historia sea una narración coherente. Las responsabilidades del identificador son solo un subconjunto que son comunes a todas las entidades.
Todavía no tenemos ninguna aplicación de singularidad. Eso no es posible dentro de una sola entidad, porque la unicidad requiere acceso al estado de todas las entidades; donde una sola entidad solo tiene acceso a la suya.
Una vez más, verificar todos los identificadores cada vez no es práctico, por lo que satisfacemos la singularidad de la manera fácil: el código que genera el siguiente identificador nunca debe repetirse.
Al final, esto significa que podemos verificar la continuidad al probar la equivalencia de dos piezas de estado diferentes en la memoria, ahorrando mucha molestia al tratar de consultar gráficos acíclicos.
También parece haber confundido el Principio de responsabilidad única (que es una muy buena idea) con un principio de responsabilidad atómica. Descomponer una responsabilidad en partes más pequeñas y más fáciles de manejar es compatible con SRP.
fuente
Bueno, depende de cómo quieras verlo.
Otra forma es: "¿El principio de responsabilidad única está violando la entidad del dominio?"
Ambas son pautas. No existe un "principio" en ninguna parte del diseño de software. Sin embargo, hay buenos diseños y malos diseños. Ambos conceptos se pueden usar de diferentes maneras para lograr un buen diseño.
fuente