Во многих случаях мои бизнес-объекты обычно бывают в ситуациях, когда информация слишком часто пересекает границы объекта. При выполнении ОО мы хотим, чтобы информация была в одном объекте, и как можно больше кода, работающего с этой информацией, должен быть в этом объекте. Однако бизнес-правила не следуют этому принципу, что доставляет мне неприятности.
В качестве примера предположим, что у нас есть Order, который имеет несколько OrderItems, который ссылается на InventoryItem, у которого есть цена. Я вызываю Order.GetTotal (), который суммирует результат OrderItem.GetPrice (), который умножает количество на InventoryItem.GetPrice (). Все идет нормально.
Но затем мы узнаем, что некоторые вещи продаются с двумя за одну сделку. Мы можем справиться с этим, если бы OrderItem.GetPrice () сделал что-то вроде InventoryItem.GetPrice (количество) и позволил InventoryItem справиться с этим.
Однако затем мы обнаруживаем, что сделка «два к одному» длится только в течение определенного периода времени. Этот период времени должен быть основан на дате заказа. Теперь мы изменим OrderItem.GetPrice () на InventoryItem.GetPrice (quatity, order.GetDate ())
Но тогда нам нужно поддерживать разные цены в зависимости от того, как долго клиент находился в системе: InventoryItem.GetPrice (amount, order.GetDate (), order.GetCustomer ())
Но затем выясняется, что сделки «два к одному» применяются не только к покупке нескольких товаров одного и того же предмета, но и нескольких для любого предмета в InventoryCategory. На этом этапе мы возбуждаем руки и просто даем InventoryItem элемент заказа и позволяем ему перемещаться по графу ссылок объекта через средства доступа, чтобы получить информацию, которая ему нужна: InventoryItem.GetPrice (this)
TL; DR Я хочу иметь низкую связь между объектами, но бизнес-правила часто вынуждают меня получать доступ к информации повсюду, чтобы принимать конкретные решения.
Есть ли хорошие методы для борьбы с этим? Другие находят ту же проблему?
источник
Ответы:
У нас был практически такой же опыт, когда я работаю, и мы решили его с помощью класса OrderBusinessLogic. По большей части макет, который вы описали, работает для большей части нашего бизнеса. Это красиво, чисто и просто. Но в тех случаях, когда вам приходится покупать любые 2 из этой категории, мы рассматриваем это как «исключение бизнеса», и класс OrderBL пересчитывает итоговые значения путем обхода необходимых объектов.
Это идеальное решение, нет. У нас все еще есть один класс, который слишком много знает о других классах, но по крайней мере мы переместили эту потребность из бизнес-объектов в класс бизнес-логики.
источник
Похоже, вам нужен отдельный объект Discount (или их список), который отслеживает все эти вещи, а затем применяет Discount (s) к Ордену, что-то вроде
Order.getTotal(Discount)
илиDiscount.applyTo(Order)
или подобное.источник
Это совершенно нормально для доступа к данным из других классов. Однако вы хотите, чтобы это были однонаправленные отношения. Например, предположим, что ClassOrder обращается к CallItem. В идеале ClassItem не должен обращаться к ClassOrder. Я думаю, что вам не хватает в вашем Классе заказа какая-то бизнес-логика, которая может или не может оправдать такой класс, как предложил Уолтер.
Изменить: Ответ на комментарий Уинстона
Я не думаю, что вам нужен объект предмета инвентаря вообще ... по крайней мере, так, как вы его используете. Вместо этого у меня был бы класс инвентаря, который управлял бы базой данных инвентаря.
Я бы сослался на предметы инвентаря по идентификатору. Каждый заказ будет содержать список идентификаторов инвентаря и соответствующее количество.
Тогда я бы посчитал сумму заказа примерно так.
Inventory.GetCost (товары, CUSTOMERNAME, дата)
Тогда у вас может быть другая вспомогательная функция, например:
Inventory.ItemsLefts (int itemID)
Inventory.AddItem (int itemID, int количество)
Inventory.RemoveItem (int itemID, int количество)
Inventory.AddBusinessRule (...)
Inventory.DeleteBusinessRule (...)
источник
Подумав об этом больше, я придумал собственную альтернативную стратегию.
Определите ценовой класс.
Inventory.GetPrice()
возвращает объект ценыТеперь класс Price (и, возможно, некоторые родственные классы) инкапсулирует логику ценообразования, и заказ не должен беспокоиться об этом. Прайс ничего не знает о Order / OrderItem, а просто вводит в него информацию.
источник