Muchas veces mis objetos comerciales tienden a tener situaciones en las que la información necesita cruzar los límites de los objetos con demasiada frecuencia. Al hacer OO, queremos que la información esté en un objeto y, en la medida de lo posible, todo el código relacionado con esa información debe estar en ese objeto. Sin embargo, las reglas comerciales no siguen este principio, lo que me causa problemas.
Como ejemplo, suponga que tenemos un Pedido que tiene un número de Artículos de pedido que se refiere a un Artículo de inventario que tiene un precio. Invoco Order.GetTotal () que suma el resultado de OrderItem.GetPrice () que multiplica una cantidad por InventoryItem.GetPrice (). Hasta ahora tan bueno.
Pero luego descubrimos que algunos artículos se venden con un trato de dos por uno. Podemos manejar esto haciendo que OrderItem.GetPrice () haga algo como InventoryItem.GetPrice (cantidad) y dejando que InventoryItem se encargue de esto.
Sin embargo, luego descubrimos que el acuerdo de dos por uno solo dura un período de tiempo particular. Este período de tiempo debe basarse en la fecha del pedido. Ahora cambiamos OrderItem.GetPrice () para que sea InventoryItem.GetPrice (quatity, order.GetDate ())
Pero luego tenemos que admitir precios diferentes dependiendo de cuánto tiempo haya estado el cliente en el sistema: InventoryItem.GetPrice (cantidad, orden.GetDate (), orden.GetCustomer ())
Pero luego resulta que las ofertas de dos por uno se aplican no solo a la compra de múltiples del mismo artículo de inventario, sino a múltiples para cualquier artículo en una categoría de inventario. En este punto, levantamos nuestras manos y simplemente le damos al InventoryItem el artículo de pedido y le permitimos viajar sobre el gráfico de referencia del objeto a través de los accesores para obtener la información que necesita: InventoryItem.GetPrice (this)
TL; DR Quiero tener un bajo acoplamiento en los objetos, pero las reglas comerciales a menudo me obligan a acceder a información de todas partes para tomar decisiones particulares.
¿Existen buenas técnicas para lidiar con esto? ¿Otros encuentran el mismo problema?
fuente
Respuestas:
Básicamente, hemos tenido la misma experiencia donde trabajo y la hemos abordado al tener una clase OrderBusinessLogic. En su mayor parte, el diseño que ha descrito funciona para la mayoría de nuestro negocio. Es agradable, limpio y simple. Pero en esas ocasiones en las que ha comprado 2 de esta categoría, tratamos eso como una "exención comercial" y hacemos que la clase OrderBL recalcule los totales atravesando los objetos necesarios.
Es una solución perfecta, no. Todavía tenemos una clase que sabe demasiado sobre las otras clases, pero al menos hemos trasladado esa necesidad fuera de los objetos de negocio a una clase de lógica de negocios.
fuente
Suena como que necesitan un objeto separado de descuento (o una lista de ellos) que realiza un seguimiento de todas esas cosas, y luego aplicar el descuento (s) de la Orden, algo así como
Order.getTotal(Discount)
oDiscount.applyTo(Order)
o similar.fuente
Está perfectamente bien acceder a datos de otras clases. Sin embargo, desea que esta sea una relación unidireccional. Por ejemplo, supongamos que ClassOrder accede a CallItem. Idealmente, ClassItem no debería acceder a ClassOrder. Lo que creo que falta en su Clase de orden es algún tipo de lógica de negocios que puede o no garantizar una clase como la sugerida por Walter.
Editar: Respuesta al comentario de Winston
No creo que necesite un objeto de inventario en absoluto ... al menos en la forma en que lo está utilizando. En cambio, tendría una clase de inventario que administrara una base de datos de inventario.
Me referiría a los artículos de inventario por una identificación. Cada pedido contendría una lista de ID de inventario y una cantidad correspondiente.
Luego calcularía el total del pedido con algo como esto.
Inventory.GetCost (Items, customerName, date)
Entonces podría tener otra función auxiliar como:
Inventory.ItemsLefts (int itemID)
Inventory.AddItem (int itemID, int cantidad)
Inventory.RemoveItem (int itemID, int cantidad)
Inventory.AddBusinessRule (...)
Inventory.DeleteBusinessRule (...)
fuente
Después de pensar más en esto, he ideado mi propia estrategia alternativa.
Definir una clase de precio.
Inventory.GetPrice()
devuelve un objeto de precioAhora la clase Price (y posiblemente algunas clases relacionadas) encapsulan la lógica de fijación de precios y el orden no tiene que preocuparse por eso. Price no sabe nada sobre Order / OrderItem, sino que simplemente recibe información.
fuente