Как изменить свойство объекта, который требует проверки базы данных? - PullRequest
0 голосов
/ 11 января 2012

У меня есть объект под названием StyleBundle.

public class StyleBundle
{
    public StylePricingType StylePricingType { get; private set;}
    public decimal Price {get; private set;}
    public IEnumerable<Style> Styles { get; set;}
    public DateTime StartDate {get; private set;}
    public TimeSpan Duration {get; private set;}
    public bool IsTransient {get; set;}

    public void ChangeStylePricingType(StylePricingType newStylePricingType)
    {
        this.StylePricingType = newStylePricingType;
    }

}

Этот объект StyleBundle имеет свойство StylePricingType.StylePricingType - это перечисление двух типов:

PerStyle

Unlimited

StylePricingType влияет на общую цену StyleBundle.Это повлияет на цену, изменив стили, сохраненные в списке стилей.Unlimited StyleBundle будет автоматически включать все доступные стили, но PerStyle StyleBundle позволит пользователю вручную выбирать, какие стили они хотят включить.

Теперь мне нужно разрешить изменение StylePricingType, если StyleBundle является переходным (В предыдущих правилах говорилось, что после того, как StyleBundle будет создан новым, вы не сможете изменить StylePricingType).

НО, чтобы внести это изменение, мне нужно выполнить проверку базы данных через репозиторий / спецификацию/ service ... иначе, но я хочу это сделать.

Проверка в основном ищет любые другие StyleBundles в течение той же продолжительности текущего StyleBundle, и проверяет, нет ли наложения в Styles в StyleBundle.

Поскольку изменение этого свойства для переходного StyleBundle требует проверки с другими сохраняемыми StyleBundles, каков наилучший способ реализации этого?

  1. Использовать инъекцию в конструктор: инжектироватьсервис в конструкцию объекта StyleBundleт е р.Мне это не нравится, потому что мне не нравится вставлять зависимости в мои сущности, если только мне это не нужно.Кроме того, поскольку мне не нравится идея внедрения зависимости в конструктор, когда она необходима только для вызова метода, который изменит StylePricingType, я вижу это как плохой дизайн.

  2. Использование внедрения метода: поскольку мне нужен только сервис для этого вызова одного метода, кажется, это имеет больше смысла.Но в то же время мне не нравится идея, что пользователь может изменить этот тип, не зная, что он выполняет запрос БД.Кроме того, я все еще внедряю сервис в свою сущность, просто по-другому, и мне действительно не нравится внедрять что-либо в мои сущности.

  3. Использование доменной службы: кажетсябыть самым явным из всех.Я мог бы создать класс StyleBundleService, у которого есть метод ChangeStylePricingType, который использует хранилище или спецификацию для запуска проверки, заданной StyleBundle.Таким образом, требование сделано в коде очень явным, но недостатком здесь является то, что код все еще может вызывать метод ChangeStylePricingType непосредственно в объекте StyleBundle, а BYPASS метод ChangeStylePricingType в сервисе, который мне нужно сделать.Даже если я установлю StylePricingType, чтобы получить; set;вместо частного набора;и избавившись от метода ChangeStylePricingType в StyleBundle, код все еще может вносить изменения, минуя службу домена.

Итак, все это кажется законным способом сделать что-то подобное,так каков наилучший / наиболее приемлемый способ сделать это с помощью DDD?Кроме того, возможно, мой объект StyleBundle пытается сделать слишком много, и его следует разбить на более мелкие классы / функции, которые позволили бы более красноречиво обрабатывать изменения этого требования?

Mike

Ответы [ 2 ]

0 голосов
/ 13 января 2012

Хотя я согласен с тем, что было бы неплохо вывести это поведение из StyleBundle, я обычно стараюсь избегать максимально возможного использования Сервисов.Чтобы быть более точным, я стараюсь не называть что-либо Сервисом, если есть известные имена шаблонов, которые лучше соответствуют тому, что вы действительно хотите, чтобы объект делал.

В вашем примере мне все еще неясно, хотите ли вы просточтобы проверить действительность StyleBundle по отношению к новому назначенному ему StylePricingType, полностью отклоняя операцию, если пакет не соответствует, или , если вы хотите настроить содержимое пакета в соответствии с новым StylePricingType.

В первом случае спецификация кажется наиболее подходящей для этого (вы упомянули в комментариях, которые вы уже используете, когда добавляете стили в комплект).Во втором вам нужен объект, который на самом деле будет действовать на Bundle, устраняя несовместимые стили.Я бы использовал StyleRuleOutStrategy / Policy с методом Enforce (), принимая Bundle в качестве параметра.В обоих случаях вы должны вызывать соответствующий метод новой Спецификации / Стратегии в установщике свойств при изменении Спецификации / Стратегии.

Обратите внимание, что часть Стратегия приобретает все свое значение, если выполняемое действие не совпадаетпри переключении на PerStyle, чем при переключении на Unlimited, но опять же из того, что вы объяснили, не ясно, в этом ли причина.

0 голосов
/ 12 января 2012

Это распространенная проблема, возникающая в DDD.Подобная проблема обсуждается Уди Даханом в этом посте .Вариант 1 обсуждается в этом вопросе.Вариант 2 обсуждается в другом месте на SO (нет точной ссылки), но, как и вы, я не фанат, хотя это самый простой и прямой способ.Вариант 3 часто ассоциируется с моделью анемичной области, однако я часто нахожу ее предпочтительной.Причина в том, что инкапсулирующий уровень сервиса является чем-то естественным как часть DDD - он предоставляет уровень домена другим уровням, таким как уровень представления или сервис открытого хоста.Кроме того, действия, выполняемые над объектами домена, могут быть представлены как объекты команд, которые обрабатываются службой.В этом случае вы можете иметь:

class ChangeStylePricingTypeCommand {
  public string StyleBundleId { get; set; }
  public StylePricingType StylePricingType { get; set; }
}

class StyleBundleService {
 IStyleBundleRepository db;

 public void Process(ChangeStylePricingTypeCommand command) {
   using (var tx = this.db.BeginTransaction()) {
    var bundle = this.db.Get(command.StyleBundleId); 

    // verification goes here.

    bundle.ChangeStylePricingType(command.StylePricingType);

    this.db.Commit();
   }
 } 
}

Служба StyleBundleService является идеальным местом для доступа к хранилищам и другим службам.

Подход, описанный Уди, влечет за собой ChangeStylePricingType, вызывающее событие домена, на которое будет подписан обработчик, который, в свою очередь, выполняет требуемую бизнес-логику.Этот подход более разделен, но более сложен и может быть излишним.Другая проблема с подходом, основанным на событиях в домене, заключается в том, что обработчик выполняется после того, как событие произошло, и, следовательно, не может предотвратить его, он может иметь дело только с последствиями.

...