Esta es una pregunta que hice hace un tiempo sobre SO, pero puede discutirse mejor aquí ...
Donde trabajo, hemos ido y venido sobre este tema varias veces y estamos buscando un control de cordura. Aquí está la pregunta: ¿Deberían los Business Objects ser contenedores de datos (más como DTO ) o también deberían contener lógica que pueda realizar alguna funcionalidad en ese objeto?
Ejemplo: tome un objeto de cliente, probablemente contiene algunas propiedades comunes (Nombre, Id, etc.), ¿ese objeto de cliente también debe incluir funciones (Guardar, Calc, etc.)?
Una línea de razonamiento dice que separe el objeto de la funcionalidad (principal de responsabilidad única) y coloque la funcionalidad en una capa u objeto de Business Logic.
La otra línea de razonamiento dice que no, si tengo un objeto de cliente solo quiero llamar a Customer.Save y listo. ¿Por qué necesito saber sobre otra clase para salvar a un cliente si estoy consumiendo el objeto?
Nuestros dos últimos proyectos han tenido los objetos separados de la funcionalidad, pero el debate se ha planteado nuevamente en un nuevo proyecto.
¿Qué tiene más sentido y por qué?
fuente
Respuestas:
Si considera que un Cliente es parte del modelo de dominio, entonces tiene sentido (especialmente dentro del contexto de DDD pero no limitado a él) tener propiedades y operaciones para ese objeto.
Dicho esto, sin embargo, creo que el ejemplo que ha utilizado es pobre y es una causa del argumento. Si habla de persistencia, los clientes generalmente no se "salvan" a sí mismos; lo que sea que estés usando para persistencia lo hará. Tiene sentido que cualquier tipo de persistencia pertenezca a la capa / partición de persistencia. Este es generalmente el pensamiento detrás del patrón de repositorio. ** Un método como Customer.UpgradeWarranty () o Customer.PromoteToPreferred () aclara el argumento.
Esto tampoco elimina la posibilidad de tener DTO . Considere la situación en la que va a pasar información del cliente a un servicio remoto, por ejemplo. Puede que no tenga sentido que un cliente cree un DTO de sí mismo para el transporte, eso es una preocupación arquitectónica, pero podría hacerse un caso en la persistencia o en la capa de red / partición / código / lo que sea que tenga. En ese caso, dicho objeto podría tener métodos que se vean así
Entonces, en resumen, tiene mucho sentido tener operaciones en un objeto de dominio que sean congruentes con operaciones lógicas en el dominio.
Busque "Ignorancia de persistencia" en Google para una serie de buenas discusiones sobre el tema ( esta pregunta SO , y su respuesta aceptada es un buen lugar para comenzar).
** Esto se vuelve un poco confuso con cierto software OR / M donde se ve obligado a heredar de una base persistente que tiene un método 'Guardar'.
fuente
En realidad, recientemente modifiqué algunos códigos para separar los objetos de los datos. La razón es que los datos se obtienen a través de un servicio separado, y es mucho más fácil pasar los datos sin procesar al / del servidor en lugar de pasar todo el objeto de un lado a otro y tener que lidiar con errores de validación en el servidor.
Para proyectos pequeños, tener objetos que contengan su lógica comercial y datos probablemente esté bien, pero para proyectos grandes, o proyectos que podrían expandirse con el tiempo, definitivamente separaría las capas.
fuente
Creo que ambas formas de hacerlo pueden tener sus beneficios, pero lo vería desde una perspectiva orientada a objetos o desde un dominio: cuáles son las responsabilidades de las diferentes clases y objetos.
Entonces, me preguntaría esto, en su caso concreto: ¿debería un cliente saber cómo salvarse?
Para mí, la respuesta sería no: lógicamente para mí no tiene sentido, y un cliente no debería tener que saber nada sobre ningún marco de persistencia (separación de responsabilidades).
En cuanto a los ejemplos de SnOrfus con Customer.UpgradeWarranty () o Customer.PromoteToPreferred (), obviamente están más orientados a la lógica de negocios que Customer.Save (). Existen diferentes enfoques para esto, pero de nuevo si se pregunta si se supone que un cliente puede actualizar su garantía, la respuesta podría ser sí o no, dependiendo de cómo lo mire:
De vuelta a su pregunta original; qué forma tiene más sentido probablemente dependerá de a quién le pregunte y su método preferido, pero lo más importante es probablemente seguir una forma de hacerlo.
Sin embargo, en mi experiencia, la separación de datos y lógica (comercial) hace que la arquitectura sea más simple, aunque no tan emocionante.
fuente
Creo que estás hablando específicamente sobre la diferencia entre el
ActiveRecord
patrón y elRepository
patrón. En el primero, las entidades saben cómo persistir, y en el segundo, el repositorio sabe sobre la persistencia. Creo que este último ofrece una mejor separación de las preocupaciones.En un sentido más amplio, si las entidades actúan más como una estructura de datos, entonces no deberían tener comportamientos, pero si tienen comportamientos, entonces no deberían usarse como una estructura de datos. Ejemplo:
Estructura de datos:
Estructura sin datos:
En el primer caso, puede navegar por el árbol de estructura de datos de su modelo sin problemas, desde cualquier parte de su código de trabajo, y eso está bien, porque lo está tratando como una estructura de datos. En el último caso, el Cliente es más como un servicio para un cliente determinado, por lo que no debe llamar a los métodos sobre el resultado. Todas las cosas que desea saber sobre el Cliente deben estar disponibles llamando a un método en el objeto Cliente.
Entonces, ¿desea que sus entidades sean estructuras de datos o servicios? Por consistencia, parece mejor quedarse con uno. En el primer caso, coloque su lógica de tipo "servicio" en otro lugar, no en la entidad.
fuente
Realmente no puedo responder a su pregunta, pero me parece curioso que también tengamos esta discusión en uno de nuestros proyectos en la escuela. A mí mismo me gustaría separar la lógica de los datos. Pero muchos de mis compañeros de clase dicen que el objeto debe contener toda la lógica Y los datos.
Trataré de resumir los hechos que mencionan:
Un objeto de clase empresarial representa una cosa, por lo que todos los datos y la lógica deben estar contenidos. (por ejemplo, si desea abrir una puerta, hágalo usted mismo, no le pregunta a otra persona. Mal ejemplo, lo sé)
Más fácil de entender el código y la funcionalidad de un objeto bu.
Menos complejidad en el diseño.
Les estoy diciendo que son flojos y lo haría así:
Sí, las clases de negocios representan cosas, por lo que contienen datos. Pero se siente mal salvarse, o incluso copiar. No puedes hacer eso en rl.
Hacer que el objeto sea responsable de todo hace que no sea bueno para la durabilidad y la mantenibilidad en el futuro. Si tiene una clase separada que es responsable de guardar, si agrega un nuevo objeto al diseño, puede implementar fácilmente su función de guardar. en lugar de codificarlo todo de nuevo en esa clase.
Al tener un objeto capaz de conservar datos, ese objeto puede mantener una conexión de base de datos y todo el tráfico de la base de datos se guía en ese objeto. (Básicamente es la capa de acceso a datos), de lo contrario, todo el objeto comercial debería mantener una conexión. (que agrega complejidad)
Bueno, de una forma u otra, voy a preguntarle a un maestro. Cuando haya hecho eso, publicaré su respuesta aquí también si lo desea. ;)
editar:
Olvidé mencionar que este proyecto era sobre una librería.
fuente
La respuesta realmente dependerá de cuál sea su arquitectura / diseño: una arquitectura DDD con un modelo de dominio será muy diferente de un modelo centrado en datos CRUD en lo que respecta al diseño de objetos.
Sin embargo, en general, tenga en cuenta que en el diseño orientado a objetos está intentando encapsular el estado y exponer el comportamiento. Esto significa que generalmente intentará que el estado asociado con un comportamiento sea lo más cercano posible a ese comportamiento; cuando no lo hace, se ve obligado a exponer el estado de una forma u otra.
En un modelo de dominio, desea separar el modelo de negocio de las preocupaciones de infraestructura, por lo que absolutamente desea evitar métodos como '.Guardar'. ¡No recuerdo la última vez que "salvé" a un cliente en la vida real!
En una aplicación CRUD, los datos son el ciudadano de primera clase, por lo que un ".Guardar" es completamente apropiado.
La mayoría de las aplicaciones importantes del mundo real tendrán una mezcla de estos paradigmas: modelo de dominio donde hay reglas comerciales complejas o que cambian rápidamente, DTO para transferir datos a través de límites, CRUD (o algo entre CRUD y un modelo de dominio, como activerecord) en otros lugares. No hay una regla única para todos.
fuente
He estado reflexionando sobre la misma pregunta durante un tiempo: creo que el componente de datos y el componente lógico deben estar separados. Creo esto porque te lleva al estado de ánimo correcto con respecto a la lógica de negocios como una interfaz para los datos que proporcionan significado.
También modifiqué el punto de Scott Whitlock desde arriba (excepto que no tengo puntos por ser un miembro nuevo), los datos o las clases de lógica de negocios realmente no deberían tener que preocuparse por cómo el objeto se almacena de forma persistente.
Dicho esto, si está tratando con un producto existente, siempre que tenga interfaces contractuales limpias, eso también está bien y se puede mantener ...
fuente