it-swarm-es.com

Objetos comerciales: ¿contenedores o funcionales?

Esta es una pregunta que hice hace un tiempo en SO, pero puede que se discuta 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 DTOs ) o deberían también contener lógica que pueda realizar alguna funcionalidad en ese objeto?.

Ejemplo: tome un objeto de cliente, probablemente contiene algunas propiedades comunes (nombre, identificación, 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 lógica empresarial.

La otra línea de razonamiento dice, no, si tengo un objeto de cliente, solo quiero llamar al cliente, guardar y terminar. ¿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 se ha vuelto a plantear el debate sobre un nuevo proyecto.

¿Qué tiene más sentido y por qué?

19
Walter

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 la causa del argumento. Si habla de perseverancia, los Clientes generalmente no se "salvan" a sí mismos; lo que sea que estés usando para la 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 DTOs . 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, esa es una preocupación arquitectónica, pero se podría argumentar en la persistencia o en la capa de red/partición/código/lo que tenga. En ese caso, tal objeto podría tener métodos que se parecen a esto

public static CustomerDTO GetDTO(Customer c) { /* ... */ }

public static Customer GetCustomer(CustomerDTO cdto) { /* ... */ }

Entonces, en resumen, tiene mucho sentido tener operaciones en un objeto de dominio que sean congruentes con las operaciones lógicas en el dominio.

Google para 'Ignorancia persistente' para una serie de buenas discusiones sobre el tema ( esta SO pregunta , y su respuesta aceptada es un buen lugar para comenzar).

** Esto se confunde un poco con cierto software OR/M donde se ve obligado a heredar de una base persistente que tiene un método 'Guardar'.

5
Steven Evers

Creo que ambas formas de hacerlo pueden tener sus beneficios, pero lo vería desde una visión orientada a objetos o impulsada por dominios: 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 empresarial que Customer.Save (). Hay diferentes enfoques para esto, pero nuevamente 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 se mire:

  • sí: un cliente puede, por supuesto, actualizar su garantía
  • no: un cliente podría preguntar ser actualizado, pero la actualización la realiza otra persona

De vuelta a su pregunta original; La forma que tenga más sentido probablemente dependerá de a quién le preguntes y de su método preferido, pero lo más importante probablemente sea ceñirte a una forma de hacerlo.

Sin embargo, en mi experiencia, separar los datos y la lógica (empresarial) hace que la arquitectura sea más simple, aunque no tan emocionante.

3
Vetle

De hecho, recientemente modifiqué un código 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 simplemente pasar los datos sin procesar hacia/desde el 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 y datos comerciales probablemente esté bien, pero para proyectos grandes o proyectos que podrían expandirse con el tiempo, definitivamente separaría las capas.

3
Rachel

Creo que estás hablando específicamente de la diferencia entre el patrón ActiveRecord y el patrón Repository. En el primero, las entidades saben cómo persistir, y en el segundo, el repositorio sabe de persistencia. Creo que este último ofrece una mejor separación de 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:

class CustomerController
{
    public int MostRecentOrderLines(Customer customer)
    {
        var o = (from order in customer.Orders
                orderby order.OrderDate desc
                select order).First();
        return o.OrderLines.ToList().Count;
    }
}

Estructura sin datos:

class Customer
{
    public int MostRecentOrderLines()
    {
        // ... same ...
    }
}

En el primer caso, puede navegar por el árbol de estructura de datos de su modelo sin problemas, desde cualquier lugar de su código de trabajo, y está bien, porque lo está tratando como una estructura de datos. En el último caso, Cliente es más como un servicio para un cliente determinado, por lo que no debe llamar a métodos en el resultado. Todo lo que desea saber sobre el cliente debe estar disponible llamando a un método en el objeto Cliente.

Entonces, ¿quiere 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.

2
Scott Whitlock

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 CRUD centrado en datos cuando se trata de diseño de objetos.

Sin embargo, en general, tenga en cuenta que en el diseño orientado a objetos está tratando de encapsular el estado y exponer el comportamiento. Esto significa que, por lo general, tratará de que el estado asociado con un comportamiento se acerque lo más posible a ese comportamiento; cuando no lo haga, se verá obligado a exponer el estado de una forma u otra.

En un modelo de dominio, desea separar el modelo comercial de las preocupaciones de infraestructura, por lo que es absolutamente necesario 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 del ciudadano de primera clase, por lo que un ".Save" es totalmente apropiado.

La mayoría de las aplicaciones importantes del mundo real tendrán una combinación de estos paradigmas: modelo de dominio donde hay reglas comerciales complejas o que cambian rápidamente, DTO para transferir datos a través de fronteras, CRUD (o algo entre CRUD y un modelo de dominio, como activerecord) en otros lugares. No existe una regla única para todos.

1
FinnNk

Realmente no puedo responder a tu pregunta, pero me parece gracioso que también estemos teniendo 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 dicen que el objeto debe contener toda la lógica Y los datos.

Intentaré resumir los hechos que traen a colación:

  • Un objeto de clase empresarial representa una cosa, por lo que todos los datos Y la lógica deben estar contenidos. (por ejemplo, si quieres abrir una puerta, hazlo tú mismo, no le preguntas a nadie más. 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 digo que son perezosos 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 el mantenimiento 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 los datos, ese objeto puede contener una conexión de base de datos y todo el tráfico de la base de datos se dirige a ese objeto. (básicamente es la capa de acceso a datos) de lo contrario, todo el objeto de negocio tendría que mantener una conexión. (que agrega complejidad)

Bueno, de una forma u otra, le voy a preguntar a un profesor. Cuando haya hecho eso, también publicaré su respuesta aquí si lo desea. ;)

editar:

Olvidé mencionar que este proyecto era sobre una librería.

1
Emerion

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 lo pone en el estado de ánimo adecuado en cuanto a la lógica empresarial como una interfaz para los datos que proporcionan significado.

También modificaría el punto de Scott Whitlock desde arriba (excepto que no tengo puntos por ser un miembro nuevo), las clases de lógica de negocios o datos realmente no deberían tener que preocuparse por cómo se almacena el objeto de manera persistente.

Dicho esto, si está tratando con un producto existente, siempre que tenga interfaces contractuales limpias, eso está bien y también se puede mantener ...

0
heretik