Esta pregunta es, en esencia, una pregunta de diseño. Usaré un ejemplo de Java/Java EE para ilustrar la pregunta.Diseño: cuando la línea entre objetos de dominio y objetos de servicio no está clara
Considere una aplicación de correo web que se genera utilizando JPA para la persistencia y EJB para la capa de servicios. Digamos que tenemos un método de servicio en nuestro EJB como esto:
public void incomingMail(String destination, Message message) {
Mailbox mb = findMailBox(destination); // who cares how this works
mb.addMessage(message);
}
Esto es aparentemente un método de negocio razonable. Presumiblemente, el objeto de buzón seguirá adjuntado y guardará los cambios de nuevo en la base de datos. Después de todo, esa es la promesa de una persistencia transparente.
el objeto de buzón tendría este método:
public void addMessage(Message message) {
messages.add(message);
}
Aquí es donde se pone complicado - suponemos que queremos tener otros tipos de buzones. Digamos que tenemos un AutoRespondingMailbox que responde automáticamente al remitente, y un HelpDeskMailbox que automáticamente abre un boleto de mesa de ayuda con cada correo electrónico recibido.
Lo natural que hacer sería extender buzón, donde AutoRespondingMailbox tiene este método:
public void addMessage(Message message) {
String response = getAutoResponse();
// do something magic here to send the response automatically
}
El problema es que nuestro objeto maibox y es subclases son "objetos de dominio" (y en este ejemplo, también Entidades JPA). Los chicos de Hibernate (y muchos otros) predican un modelo de dominio no dependiente, es decir, un modelo de dominio que no depende de los servicios proporcionados por contenedor/tiempo de ejecución. El problema con dicho modelo es que el método AutoRespndingMailbox.addMessage() no puede enviar un correo electrónico porque no puede acceder, por ejemplo, a JavaMail.
El mismo problema ocurriría con HelpDeskMailbox, ya que no podría acceder a WebServices o inyección JNDI para comunicarse con el sistema HelpDesk.
Así que uno se ve obligado a poner esta funcionalidad en la capa de servicio, así:
public void incomingMail(String destination, Message message) {
Mailbox mb = findMailBox(destination); // who cares how this works
if (mb instanceof AutoRespondingMailbox) {
String response = ((AutoRespondingMailbox)mb).getAutoResponse();
// now we can access the container services to send the mail
} else if (mb instanceof HelpDeskMailbox) {
// ...
} else {
mb.addMessage(message);
}
}
tener que utilizar instanceof de esa manera es el primer signo de un problema. Tener que modificar esta clase de servicio cada vez que quiera crear una subclase de Buzón es otro signo de un problema.
¿Alguien tiene las mejores prácticas sobre cómo se manejan estas situaciones? Algunos dirían que el objeto Mailbox debería tener acceso a los servicios del contenedor, y esto puede hacerse con un poco de fudging, pero definitivamente está luchando contra el uso previsto de JPA para hacerlo, ya que el contenedor proporciona inyección de dependencia en todas partes excepto en Entidades, indicando claramente que este no es un caso de uso esperado.
Entonces, ¿qué se espera que hagamos? ¿Llenar nuestros métodos de servicio y renunciar al polimorfismo? Nuestros objetos quedan automáticamente relegados a estructuras de estilo C y perdemos la mayor parte del beneficio de OO.
El equipo de Hibernate diría que debemos dividir nuestra lógica empresarial entre la capa de dominio y la capa de servicio, poniendo toda la lógica que no depende del contenedor en las entidades de dominio, y poniendo toda la lógica que depende de el contenedor en la capa de servicios. Puedo aceptar que, si alguien puede darme un ejemplo de cómo hacerlo sin tener que abandonar por completo el polimorfismo y recurrir a instanceof y otras tales maldad
Creo que se olvidó de la intención de mi pregunta. Olvide los detalles del ejemplo y suponga que algunas subclases de una Entidad necesitaban un comportamiento que dependiera de algún servicio proporcionado por el contenedor. – TTar
Estoy de acuerdo con esto. El problema es que su objeto de dominio ya no es un simple titular de datos, pero ahora tiene un comportamiento adjunto (con impactos en la persistencia). Personalmente, esto se siente como algo que debería manejarse a nivel de servicio. –
Entonces, si un objeto de dominio es un simple titular de datos, ¿no es mi objeto de dominio solo una estructura? ¿No es la definición de diseño orientado a objetos que los datos y el comportamiento se combinan en objetos? – TTar