2009-01-12 19 views
21

En this pregunta a alguien replies "¡Nunca dejes que las implementaciones de objetos de dominio llamen a los servicios por sí mismos!". ¿Es esta afirmación una regla dura de DDD o depende de su propia aplicación y arquitectura?Objetos y servicios de dominio

ejemplo artificioso:

Como ejemplo vamos a suponer que tenemos un objeto UserImage en nuestro modelo que se rellena a partir de una imagen cargada por un usuario. Y luego supongamos que podemos enviar esta imagen a un servicio de terceros que pueda identificar huellas dactilares y devolver un Guid si se encuentra una coincidencia.

public IThumbPrintService { 
    Guid FindMatch(Bitmap image); 
} 

public class UserImage { 
    public Bitmap Image {get; set;} 
    public Guid ThumbPrintId {get; set;} 
    public bool FindThumbPrintMatch() { 
     // Would you call the service from here? 
     ThumbPrintId = _thumbPrintService.FindMatch(this.Image); 
     return ! ThumbPrintId.CompareTo(Guid.Empty); 
    } 
} 

public class RoboCopUserImageService : IUserImageService { 
    // Or move the call to a service method 
    // since it depends on calling a separate service interface 
    public bool FindThumbPrintMatch(UserImage userImage) { 
     userImage.ThumbPrintId = _thumbPrintService.FindMatch(userImage.Image); 
     return !userImage.ThumbPrintId.CompareTo(Guid.Empty);    
    } 
} 

¿Qué se evita u obtiene al no permitir que los objetos de dominio llamen a los servicios por su cuenta?

EDITAR: ¿Hay algún artículo en línea que debata sobre este tema específico?

Respuesta

43

Este es el Spreadsheet Conundrum: does the phone dial the phone number, or does the phone number dial itself on the phone?

Puede ser que Double Dispatch sea interesante de leer, aunque overkill in your situation, I reckon.

El Single Responsibility Principle es often at odds with the OO tenet de Tell, Don't Ask. Mi sensación sobre el tema ha oscilado, y se han asentado en las siguientes condiciones cuando la lógica debe entrar en un objeto de dominio:

En su situación, optaría por no realizar la llamada al servicio dentro del objeto de entidad, principalmente porque el servicio no parece estar relacionado con su dominio, sino más relacionado con la persistencia. Los objetos de dominio deben combinarse con los conceptos de dominio, y no creo que el servicio que brindó califique.

Un ejemplo en el que creo que llamar a un servicio en una entidad podría ser aceptable sería si su aplicación utilizara un servidor de flujo de trabajo de terceros para administrar partes de su estado. Básicamente, este es el State Pattern con los estados definidos en tiempo de ejecución.

Creo que es aceptable tener domainObject.moveToNextState() (suponiendo que este código "tiene sentido" en su lenguaje ubicuo) llame al servicio que habla con su servidor porque el servidor de flujo de trabajo administra una parte del modelo de dominio.

Agregaré que DDD está muy interesado en seguir el idioma del dominio. ¿Escuchas a los expertos en el dominio que dicen "la imagen de un usuario encuentra si su huella dactilar coincide con la del servicio del vendedor XYZ"? ¿O dicen "El servicio del vendedor XYZ, con una huella dactilar, indica si existe la huella digital"? Ve con el que tenga más sentido en tu dominio.

algunos pensamientos más (he reflexionado sobre este tema mucho porque es fundamental para el diseño):

  • En el libro de Evans DDD, una entidad Cuenta tiene métodos como de crédito (monto) , débito (Cantidad), transferencia a (Cuenta, Importe) y acumular(), pero un Servicio de transferencia de fondos tiene un método de transferencia (Cuenta, Cuenta, Importe). El método transferTo no llama a ningún servicio, sino que simplemente maneja la lógica que implica las cuentas, como el abono y el abono de los montos correctos.

    El FundsTransferService, además de la coordinación, tiene sus propias reglas para verificar, reglas que no se ajustan a las cuentas. La cantidad exacta de crédito o débito podría involucrar a partes externas. Esto hace que sea incómodo transferir para llamar al servicio.

  • Para objetos simples, como la UserImage, la lógica de dominio significativa que puede caber en el objeto en sí puede ser escasa porque no es, por lo que puedo decir, un agregado. Agregados, creo, presentan más de una oportunidad para albergar la lógica de dominio. El ejemplo de Cuenta es probablemente un Agregado.
+0

Gracias, el acertijo de hoja de cálculo hace este problema mucho más claro ahora. También me gusta cómo sugieres verbalizar el problema a los expertos del dominio para determinar qué enfoque tiene más sentido. –

+1

Guau, respuesta brillante, muy clara, muy detallada. ¡Me gustaría darle más de una votación! – Guillaume

+0

Gracias por los elogios. El contenido de esta respuesta es realmente una síntesis de los efectos de mi TOC no diagnosticado. Las preguntas que plantean DDD y OO nunca dejan de fascinarme. – moffdub

2

Una desventaja que veo es que permite a su objeto de dominio para llamar a los servicios puede hacer más difícil para serializar, o al menos causar algunos problemas después de la serialización cuando alguien en el otro lado llama a su método (s) de servicio.

0

Si permite que un Objeto de entidad llame a un servicio, está realizando dos roles Objeto de datos y Objeto de servicio. Generalmente, cada objeto debe tener responsabilidad, no solo en la implementación sino también en el uso.

En su caso, la imagen de usuario humilde parece ser tanto una imagen como un reconocedor de huellas digitales.

+0

El ejemplo se inventó en el acto. La verdadera pregunta es si los objetos de tu dominio deben llamar a los servicios o no, y el problema de los acertijos de hoja de cálculo te da en la cabeza. ¡Depende! –

+0

Gracias por aclarar su respuesta. ¿Qué sucede si su objeto de entidad tiene un método como Account.Debit (amount) que necesita hacer uso de un servicio para completar la acción (por ejemplo, actualizar un repositorio, llamar a un servicio de validación o enviar una notificación)? –

+0

Se encargaría de eso haciendo que AccountService acepte un simple objeto Cuenta como argumento para un método de débito. –

0

Creo que es mejor no llamar repositorios o servicios de entidades u objetos de valor, pero a veces es necesario, por ejemplo, si una entidad debe devolver otra entidad que debe cargarse desde la base de datos pero no puede navegar hacia ella usando un gráfico de objetos. Luego, el principio de inversión de dependencia viene a ayudar, lo que significa que las entidades y los objetos de valor dependen de las interfaces de servicios y repositorios y no de las implementaciones.

Cuestiones relacionadas