Мы пытаемся переместить данные из нашего раздутого уровня Service в наш уровень Domain, используя подход DDD. В настоящее время в наших сервисах много бизнес-логики, которая распространена повсеместно и не получает наследства.
У нас есть центральный класс Domain, который находится в центре большинства нашей работы - Trade. Объект Trade будет знать, как оценивать себя, как оценивать риск, подтверждать себя и т. Д. Затем мы можем заменить условные выражения полиморфизмом. Например: SimpleTrade будет оценивать себя в одну сторону, а ComplexTrade - в другую.
Тем не менее, мы обеспокоены тем, что это приведет к раздуванию торговых классов. Он действительно должен отвечать за собственную обработку, но размер класса будет увеличиваться в геометрической прогрессии по мере добавления новых функций.
Итак, у нас есть выбор:
- Поместите логику обработки в класс Trade. Логика обработки теперь полиморфна в зависимости от типа сделки, но класс Trade теперь имеет несколько функций ответственности (ценообразование, риск и т. Д.) И является большим
- Поместите логику обработки в другой класс, такой как TradePricingService. Больше не полиморфен с деревом наследования Trade, но классы меньше и их проще тестировать.
Какой будет предложенный подход?
Ответы:
Если вы собираетесь управлять доменом, подумайте о том, чтобы рассматривать свой класс Trade как совокупный корень и разделять его обязанности на другие классы.
Вы не хотите иметь подкласс Trade для каждой комбинации цены и риска, поэтому в сделке могут содержаться объекты Price и Risk (состав). Объекты Price и Risk выполняют фактические вычисления, но не видны ни одному классу, кроме Trade. Вы можете уменьшить размер Trade, не подвергая свои новые классы внешнему миру.
Попробуйте использовать композицию, чтобы избежать больших деревьев наследования. Слишком большое наследование может привести к ситуациям, когда вы пытаетесь использовать поведение, которое не соответствует модели. Лучше перенести эти обязанности в новый класс.
источник
Ваш вопрос определенно заставляет меня думать о шаблоне стратегии . Затем вы можете поменять различные стратегии торговли / ценообразования, аналогичные тому, что вы называете
TradePricingService
.Я определенно думаю, что совет, который вы получите, это использовать композицию вместо наследования.
источник
Одним из возможных решений, которое я использовал в аналогичном случае, является шаблон проектирования адаптера (на странице, на которую есть ссылки, содержится много примеров кода). Возможно в сочетании с шаблоном дизайна делегирования для быстрого доступа к основным методам.
По сути, вы разделяете функциональные возможности трейдера на несколько разделенных областей - например, обработка цен, риски, проверка - все это могут быть разные области. Затем для каждой области вы можете реализовать отдельную иерархию классов, которая обрабатывает эту точную функциональность в различных необходимых вариантах - все это общий интерфейс для каждой области. Затем основной класс Trader сводится к самым базовым данным и ссылкам на ряд объектов-обработчиков, которые могут быть созданы при необходимости. подобно
Одним из основных преимуществ этого подхода является то, что возможные комбинации, например, цены и трюки, полностью разделены и, следовательно, могут быть объединены по мере необходимости. Это довольно сложно с однопоточным наследованием большинства языков программирования. Решение о том, какую комбинацию использовать, можно рассчитать очень поздно :-)
Я обычно стараюсь держать классы адаптера - например, подклассы
IPriceCalculator
выше - без сохранения состояния. Т.е. эти классы не должны содержать локальных данных, если это возможно, чтобы уменьшить количество экземпляров, которые должны быть созданы. Поэтому я обычно предоставляю основной адаптированный объект в качестве аргумента во всех методах - какgetPrice(ITrader)
описано выше.источник
не могу много сказать о вашем домене, но
... это запах для меня. Я, вероятно, попытался бы набросать различные обязанности класса и в конечном итоге разложить его на разные совокупности. Агрегаты будут затем построены вокруг ролей и / или точек зрения заинтересованных сторон / экспертов в данной области. Если цена и риск вовлечены в один и тот же вариант поведения / использования, они, вероятно, принадлежат к одному и тому же агрегату. Но если они не связаны, они могут принадлежать к отдельным совокупностям.
Может быть, RiskEvaluation может быть отдельной сущностью в вашем домене, в конечном итоге с определенным жизненным циклом (я не могу сказать, я просто спекулирую ... вы знаете свой домен, я не знаю), но ключ заключается в создании неявных понятий явное и во избежание связи, которая не обусловлена поведением, а только устаревшей связью данных
В общем, я бы подумал об ожидаемом поведении и различных жизненных циклах участвующих компонентов. Простое добавление поведения поверх сгруппированных данных создает раздутые объекты. Но данные сгруппированы в соответствии с существующим дизайном, управляемым данными, поэтому нет необходимости придерживаться этого.
источник