Oft haben meine Geschäftsobjekte Situationen, in denen Informationen zu oft Objektgrenzen überschreiten müssen. Wenn Sie OO ausführen, möchten wir, dass sich Informationen in einem Objekt befinden und dass sich der gesamte Code, der sich mit diesen Informationen befasst, so weit wie möglich in diesem Objekt befindet. Die Geschäftsregeln folgen jedoch nicht diesem Prinzip, was mir Probleme bereitet.
Nehmen wir als Beispiel an, wir haben eine Bestellung mit einer Anzahl von OrderItems, die sich auf ein InventoryItem mit einem Preis bezieht. Ich rufe Order.GetTotal () auf, das das Ergebnis von OrderItem.GetPrice () summiert, das eine Menge mit InventoryItem.GetPrice () multipliziert. So weit, ist es gut.
Aber dann stellen wir fest, dass einige Artikel mit zwei für einen Deal verkauft werden. Wir können dies bewältigen, indem OrderItem.GetPrice () so etwas wie InventoryItem.GetPrice (Menge) ausführt und InventoryItem damit umgehen lässt.
Dann stellen wir jedoch fest, dass der Zwei-für-Eins-Deal nur für einen bestimmten Zeitraum gilt. Dieser Zeitraum muss auf dem Datum der Bestellung basieren. Jetzt ändern wir OrderItem.GetPrice () in InventoryItem.GetPrice (quatity, order.GetDate ())
Aber dann müssen wir unterschiedliche Preise unterstützen, je nachdem, wie lange der Kunde im System ist: InventoryItem.GetPrice (Menge, Bestellung.GetDate (), Bestellung.GetCustomer ())
Es stellt sich jedoch heraus, dass die Zwei-für-Eins-Angebote nicht nur für den Kauf mehrerer Artikel desselben Inventargegenstands gelten, sondern für mehrere Artikel in einer Inventarkategorie. An diesem Punkt erheben wir unsere Hände und geben dem InventoryItem einfach die Bestellposition und lassen es über Accessoren über das Objektreferenzdiagramm fahren, um die benötigten Informationen zu erhalten: InventoryItem.GetPrice (this)
TL; DR Ich möchte eine geringe Kopplung in Objekten haben, aber Geschäftsregeln zwingen mich oft dazu, von überall auf Informationen zuzugreifen, um bestimmte Entscheidungen zu treffen.
Gibt es gute Techniken, um damit umzugehen? Finden andere das gleiche Problem?
quelle
Antworten:
Wir haben im Grunde die gleiche Erfahrung gemacht, in der ich arbeite, und wir haben sie mit einer OrderBusinessLogic-Klasse angegangen. Das von Ihnen beschriebene Layout funktioniert größtenteils für den Großteil unseres Geschäfts. Es ist schön und sauber und einfach. In den Fällen, in denen Sie 2 aus dieser Kategorie gekauft haben, behandeln wir dies als "Geschäftsausführung" und lassen die OrderBL-Klasse die Gesamtsummen neu berechnen, indem sie die benötigten Objekte durchlaufen.
Ist es eine perfekte Lösung, nein. Wir haben immer noch eine Klasse, die viel zu viel über die anderen Klassen weiß, aber zumindest haben wir dieses Bedürfnis aus den Geschäftsobjekten in eine Geschäftslogikklasse verschoben.
quelle
Klingt wie Sie benötigen ein eigenes Discount - Objekt (oder eine Liste von ihnen) , die den Überblick über all das Zeug hält, und setzt dann den Rabatt (n) an den Orden, so etwas wie
Order.getTotal(Discount)
oderDiscount.applyTo(Order)
oder ähnliches.quelle
Es ist vollkommen in Ordnung, auf Daten aus anderen Klassen zuzugreifen. Sie möchten jedoch, dass dies eine einseitige Beziehung ist. Angenommen, ClassOrder greift auf CallItem zu. Im Idealfall sollte ClassItem nicht auf ClassOrder zugreifen. Was ich denke, dass Sie in Ihrer Auftragsklasse fehlen, ist eine Art Geschäftslogik, die eine Klasse wie die von Walter vorgeschlagene rechtfertigen kann oder nicht.
Bearbeiten: Antwort auf Winstons Kommentar
Ich glaube nicht, dass Sie überhaupt ein Inventargegenstandsobjekt benötigen ... zumindest so, wie Sie es verwenden. Ich hätte stattdessen eine Inventarklasse, die eine Inventardatenbank verwaltet.
Ich würde auf Inventargegenstände durch eine ID verweisen. Jede Bestellung würde eine Liste von Inventar-IDs und eine entsprechende Menge enthalten.
Dann würde ich die Summe der Bestellungen mit so etwas berechnen.
Inventory.GetCost (Artikel, Kundenname, Datum)
Dann könnten Sie andere Hilfsfunktionen haben wie:
Inventory.ItemsLefts (int itemID)
Inventory.AddItem (int itemID, int Quantity)
Inventory.RemoveItem (int itemID, int Quantity)
Inventory.AddBusinessRule (...)
Inventory.DeleteBusinessRule (...)
quelle
Nachdem ich mehr darüber nachgedacht habe, habe ich mir eine eigene alternative Strategie ausgedacht.
Definieren Sie eine Preisklasse.
Inventory.GetPrice()
gibt ein Preisobjekt zurückJetzt verkapselt die Preisklasse (und möglicherweise einige verwandte Klassen) die Logik der Preisgestaltung, und die Bestellung muss sich nicht darum kümmern. Price weiß nichts über Order / OrderItem, stattdessen werden einfach Informationen eingegeben.
quelle