Souvent, mes objets métier ont tendance à avoir des situations où les informations doivent traverser trop souvent les limites des objets. En faisant OO, nous voulons que les informations soient dans un objet et autant que possible tout le code traitant de ces informations devrait être dans cet objet. Cependant, les règles commerciales ne suivent pas ce principe, ce qui me pose problème.
À titre d'exemple, supposons que nous avons une commande qui a un certain nombre de OrderItems qui se réfère à un InventoryItem qui a un prix. J'appelle Order.GetTotal () qui résume le résultat de OrderItem.GetPrice () qui multiplie une quantité par InventoryItem.GetPrice (). Jusqu'ici tout va bien.
Mais ensuite, nous découvrons que certains articles sont vendus avec une offre deux pour un. Nous pouvons gérer cela en demandant à OrderItem.GetPrice () de faire quelque chose comme InventoryItem.GetPrice (quantité) et en laissant InventoryItem s'en occuper.
Cependant, nous découvrons ensuite que l'accord deux pour un ne dure que pour une période donnée. Cette période doit être basée sur la date de la commande. Maintenant, nous changeons OrderItem.GetPrice () pour être InventoryItem.GetPrice (quatity, order.GetDate ())
Mais ensuite, nous devons prendre en charge différents prix en fonction de la durée de vie du client dans le système: InventoryItem.GetPrice (quantité, order.GetDate (), order.GetCustomer ())
Mais il s'avère que les offres deux pour un s'appliquent non seulement à l'achat de plusieurs articles du même inventaire, mais à l'achat de plusieurs articles dans une catégorie d'inventaire. À ce stade, nous levons la main et donnons simplement à InventoryItem l'élément de commande et lui permettons de parcourir le graphique de référence de l'objet via des accesseurs pour obtenir les informations dont il a besoin: InventoryItem.GetPrice (this)
TL; DR Je veux avoir un faible couplage dans les objets, mais les règles métier m'obligent souvent à accéder à des informations de partout pour prendre des décisions particulières.
Existe-t-il de bonnes techniques pour y faire face? D'autres trouvent-ils le même problème?
la source
Réponses:
Nous avons essentiellement eu la même expérience où je travaille et nous l'avons résolue en ayant une classe OrderBusinessLogic. Pour la plupart, la disposition que vous avez décrite fonctionne pour la majorité de nos activités. C'est agréable et propre et simple. Mais dans les cas où vous en avez acheté 2 dans cette catégorie, nous traitons cela comme une "exécution commerciale" et la classe OrderBL recalcule les totaux en parcourant les objets nécessaires.
Est-ce une solution parfaite, non. Nous avons encore une classe qui en sait beaucoup trop sur les autres classes, mais au moins nous avons déplacé ce besoin hors des objets métier et dans une classe de logique métier.
la source
On dirait que vous avez besoin d'un objet Discount séparé (ou d'une liste d'entre eux) qui garde une trace de tout cela, puis appliquez les rabais à la commande, quelque chose comme
Order.getTotal(Discount)
ouDiscount.applyTo(Order)
ou similaire.la source
Il est parfaitement correct d'accéder aux données d'autres classes. Cependant, vous voulez que ce soit une relation unidirectionnelle. Par exemple, supposons que ClassOrder accède à CallItem. Idéalement, ClassItem ne devrait pas accéder à ClassOrder. Ce que je pense que vous manquez dans votre classe de commande est une sorte de logique commerciale qui peut ou non justifier une classe telle que celle suggérée par Walter.
Edit: Réponse au commentaire de Winston
Je ne pense pas que vous ayez besoin d'un objet d'objet d'inventaire ... du moins de la manière dont vous l'utilisez. J'aurais plutôt une classe d'inventaire qui gérait une base de données d'inventaire.
Je me référerais aux articles d'inventaire par un ID. Chaque commande contiendrait une liste d'ID d'inventaire et une quantité correspondante.
Ensuite, je calculerais le total de la commande avec quelque chose comme ça.
Inventory.GetCost (Items, customerName, date)
Ensuite, vous pourriez avoir une autre fonction d'aide comme:
Inventory.ItemsLefts (int itemID)
Inventory.AddItem (int itemID, int quantity)
Inventory.RemoveItem (int itemID, int quantity)
Inventory.AddBusinessRule (...)
Inventory.DeleteBusinessRule (...)
la source
Après y avoir réfléchi davantage, j'ai trouvé ma propre stratégie alternative.
Définissez une classe de prix.
Inventory.GetPrice()
renvoie un objet prixMaintenant, la classe de prix (et éventuellement certaines classes connexes) résume la logique de tarification et l'ordre n'a pas à s'en soucier. Price ne sait rien de Order / OrderItem au lieu d'avoir simplement des informations.
la source