Подход к разработке инвентаризации (наследование против дженериков) - PullRequest
0 голосов
/ 02 июня 2011

Привет! Я пытаюсь решить, какой подход лучше всего реализовать в следующем сценарии:

Транспортное средство и Деталь - это "предметы", которые могут быть Предметом в Инвентаризации. Транспортное средство имеет обычный VIN, год, марку, модель, тип и т. Д., И т. Д., В то время как деталь имеет PartNumber, QuantityOnHand, IsPartOfSet, Vendor ... При «складировании» в Инвентаризации как товара оба имеют RetailPrice, PurchasePrice, PurchaseDate, но в то же время имеют множество других свойств, которые не являются общими (например, у транспортного средства есть CurrentM Пробег, NewOrUsed и т. д. и т. д., в то время как у части есть TreshholdCount, LastCountDate и т. д. и т. д.) Таким образом, вы можете видеть, что и Деталь, и Автомобиль могут быть в Инвентаризации, но у них очень мало общих свойств (больше, чем у них) ...

В сценарии выше я пытаюсь выбрать один из нескольких подходов:

Вариант 1 - Отдельные классы для всего (без наследования)

  • Автомобиль - общие свойства автомобиля (VIN, год, марка, модель и т. Д.)
  • VehicleInventoryItem - содержит ссылку на Vehicle и содержит другие специфические для инвентаря свойства (цены, гарантии, статус)
  • VehicleInventoryManager - синглтон с бизнес-логикой, добавление, удаление, уведомление и т. Д. И т. Д.
  • Часть
  • PartInventoryItem
  • PartInventoryManager

Я думаю, что этот подход является наиболее гибким, хотя и страдает от повторения некоторых свойств. У менеджеров тоже могут быть самые разные методы ...

Вариант 2 - Базовый класс простого наследования

  • Автомобиль - такой же, как вариант 1
  • Деталь - так же, как вариант 1
  • InventoryItem - базовый класс
  • VehicleInventoryItem - расширяет InventoryItem, ссылки Автомобиль
  • PartInventoryItem - расширяет InventoryItem, ссылается на Part
  • InventoryManager - все методы принимают InventoryItem в качестве параметров

При таком подходе меня беспокоит загрязнение InventoryManager различными операциями, необходимыми для деталей по сравнению с транспортными средствами

Вариант 3 - Обобщения

  • Item - где T будет частью или транспортным средством (я могу даже сказать более конкретно, например, - VehicleItem: Item)
  • Инвентарь - содержит ссылку на элемент
  • InventoryManager - синглтон, работающий на T

В этом подходе меньше классов, но я снова беспокоюсь об InventoryManager

Резюме

  1. Транспортное средство и деталь имеют очень мало свойств при хранении в Inventory.
  2. Управление запасами для Транспортного средства и его частей также будет в основном различным (детали «переупорядочиваются», когда количество в наличии мало, при продаже транспортного средства аналогичная может быть приобретена, но она уникальна)
  3. В моем сценарии не будет других объектов / моделей, которые можно было бы "запасать" (находиться в инвентаре любого вида)

Вопросы

Что думает сообщество? Есть ли другой подход (возможно, интерфейсы?) Если 2 объекта домена имеют хотя бы одно свойство (например, PurchasePrice), следует ли иметь такое наследование (например, вариант 2 или 3)

Ответы [ 4 ]

2 голосов
/ 02 июня 2011

Я бы создал абстрактный базовый класс, представляющий любой предмет, который потенциально находится в инвентаре.Что-то вроде InventoryItem.У него будут основные свойства, о которых вы упомянули, что у них есть все общее: RetailPrice, PurchasePrice, PurchaseDate и т. Д. И он обеспечит реализацию по умолчанию (где это уместно) для определенных свойств и методов.

Тогда я бы унаследовализ этого класса и специализируйте его для каждого из предметов, которые вы планируете на складе: Vehicle и Part.Переопределите методы, которые вам нужны, реализуйте все методы, помеченные как abstract, и добавьте все дополнительные функции и / или бизнес-логику, которые требуются определенным подклассам.

Нет абсолютно никакой причины использоватьинтерфейс здесь.Как вы упоминаете, все вещи, которые вы продаете, имеют много общих признаков.У них есть некоторые дополнительные , и некоторые функции могут работать по-другому , но есть много того, что принципиально одинаково.Нет причин дублировать эту функциональность в разных местах.Использование абстрактного базового класса дает вам возможность обеспечить реализацию по умолчанию.

Класс InventoryManager вам вообще не нужен: вы правы, подозревая, что ему нужно знать о различныхтипы подклассов.Просто позвольте производным классам делать всю работу.Вот для чего они нужны.

Подробнее о том, почему абстрактные базовые классы обычно превосходят интерфейсы, см. В следующих ответах:

И я не могу себе представить, почему дженерики здесь актуальны.Это специальный инструмент, используемый для решения конкретной проблемы, а не общий шаблон проектирования.Если вам нужны дженерики, используйте их.Но хорошо продуманный дизайн, который использует преимущества наследования и полиморфизма, также значительно снижает вероятность того, что они вам понадобятся.

1 голос
/ 02 июня 2011

Я бы создал базовый класс: назовем его InventoryItem, содержащий все общие свойства (RetailPrice, PurchasePrice, PurchaseDate и т. Д.)

Part и Vehicle будут наследоваться от InventoryItem и расширять его любыми необходимыми им свойствами.

Я бы тогда создал базовый класс с именем InventoryManager, от которого наследуются VehicleManager и PartManager. InventoryManager будет содержать всю совместно используемую логику для управления запасами, а подклассы будут расширять его с помощью любой необходимой им функциональности.

У меня сложилось впечатление, что вы довольно рано в процессе проектирования. Я бы не стал пытаться придумать идеальный дизайн для этого, так рано. Просто создайте что-то базовое, изменяйте и расширяйте его по мере продвижения, потому что когда вы начнете создавать и использовать API, вы лучше поймете проблему.

«Если сомневаешься, оставь это.»

0 голосов
/ 02 июня 2011

Может быть, я что-то упускаю, но я не понимаю вашу озабоченность по поводу "загрязнения" в InventoryManager. Если это проблема, это потребовало бы отдельного класса. Любой другой класс, который вы описали, имеет общие функциональные возможности (по крайней мере, их идентификаторы), так что наследование может показаться в порядке вещей.

Я думаю, однако, что вы захотите использовать сочетание технологий. Вы будете использовать наследование с интерфейсами (для сравнения, например) и обобщениями (для списков). Одно не обязательно исключает другое.

0 голосов
/ 02 июня 2011

Из краткого обзора вашего описания я хотел бы предложить поместить методы, связанные с инвентаризацией, в элементы интерфейса. Если вам нужны отношения между транспортными средствами и деталями, у вас всегда может быть свойство на ваших деталях, чтобы ссылаться на транспортное средство, с которого они поступили, или наоборот (или, возможно, на оба, если вам нужно выполнить поиск в обоих направлениях). Похоже, это разделяет заботу о решении задач, связанных с инвентаризацией, на определенный класс. Надеюсь, это поможет.

...