1

Сначала позвольте мне описать освещенный бит домен. У нас есть сайт, на котором клиент может разместить заказ. Чтобы разместить заказ, клиент должен предоставить некоторые данные. Этот процесс разделен на этапы. На каждом шаге клиент предоставляет только часть данных. Когда клиент завершает последний шаг - все данные, необходимые для заказа, готовы.DDD: Сущность технически, но выглядит как объект ценности?

У нас есть предприятие StepsProgression. Внутри находится массив значений объектов «Шаг». Они ничего не хранят, поэтому они просты и идеально подходят для создания объектов ценности. Но чтобы сохранить данные пользователя на всех этапах, внутри StepsProgression есть также объект StepsData.

И здесь возникает проблема. StepsData будет иметь сеттеры, чтобы установить пользовательские данные. Так что это должно быть Сущность. Но с точки зрения домена это не сущность. Это объект Value, потому что меня не интересует его личность. Я могу заменить его объектом с теми же данными, и это нормально.

Что вы можете посовещаться в этой ситуации?

EDIT 1

О домене снова

Мы действительно имеем систему бронирования. И мы спросили экспертов домена, и у нас действительно есть разные шаги (или этапы), чтобы заполнить некоторые конкретные данные, чтобы заказать элемент заказа для пользователя. Таким образом, концепция Step и StepsProgressions в порядке. Он не связан с пользовательским интерфейсом. Например, на стороне пользовательского интерфейса мы заполняем данные для двух шагов одновременно.

ответ

1

Ценностный объект может иметь геттеры и сеттеры. Похоже, в вашем случае StepsData описывает состояние объекта (StepsProgression), которое делает его кандидатом на значение объекта. У вас может быть свойство объекта value в самом объекте значения. Объект ценности, являющийся самодостаточным, делает его принципиально более легким в работе. Для пуриста DDD объекты значения неизменяемы, побочные эффекты свободны и легко проверяются.

+1

Будьте осторожны с сеттерами: VO являются неотразимыми, поэтому сеттеры должны возвращать новый объект –

+0

Спасибо! StepsData действительно является чем-то вроде состояния, потому что когда мы что-то наполняем, мы меняем состояние. Таким образом, я могу сделать StepsData объектом значения с сеттерами, который вернет мне новый объект значения, который я буду использовать для замены старого? – Clickbeetle

1

Из моих редких знаний, читая ваш вопрос/описание, мне кажется, что вы строите какой-то интернет-магазин, систему бронирования или что-то подобное.

Предположительно, пожалуйста, внимательно проанализируйте свой домен. Задайте себе вопрос: что ваш домен действительно есть, и если StepsProgression, Step и StepData действительно «Домен относится к» такой системы заказа ...?

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

В этом случае они не будут являться объектом Entity или Value, потому что они даже не являются частью модели домена.

Я предложил бы вернуться к доске и первого запуска моделирования модель предметной области, состоящей только из области конкретных объектов (+ много больше), не имея интерфейс или использовать случаи в виду слишком много:

- Order (Entity) 
- OrderNumber (Value Object) 
- Customer (Entity) 
- PaymentType (Entity) 
- OrderTotal (Value Object) 
- … 

Объединив их в подходящие Агрегаты (границы транзакций), сохранив их с помощью Репозиториев и обработав их с помощью доменных служб, вы должны иметь возможность создать «богатую» модель домена.

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

Впоследствии могут потребоваться некоторые мелкие рефакторинги для модели домена, но имейте в виду, что проблемы, связанные с пользовательским интерфейсом, приложениями или инфраструктурой, должны соответствовать модели домена, а не «утечки» в нее.

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

+0

Спасибо за ответ! Мы действительно говорим о системе бронирования. И процесс заполнения данных для бронирования, разделенный на этапы, является нашей основной областью. Это наше преимущество перед конкурентами. И модель шагов очень отличается от UI (потому что в пользовательском интерфейсе много шагов объединены и расположены на одной странице). Таким образом, вы хорошо разбираетесь в советах, но у нас уже есть отдельная модель заказа и отдельная модель Шагов. – Clickbeetle

0

Сначала перепроверьте домен для StepsProgression: если мы спросим эксперта домена о шагах нашего процесса, я думаю, мы получим приемлемый ответ. Тогда мы можем сказать, что это часть нашего домена.

Далее, как вы говорите, это лицо или ВО? Да, он выглядит как объект ценности и фактически является объектом значения, так как вы не заботитесь об идентичности всего набора данных, он не имеет уникального значения (если я не понял, что неправильно неправильно).

Если у вас есть пользовательский интерфейс, как и мастер формы и входы каждый шаг разные, я бы Реализовать так:

public class StepsProgression 
{ 
    private readonly string _userId; 
    public Step1 step1 { get; set; } 
    public Step2 step2 { get; set; } 
    public Step3 step3 { get; set; } 

    public StepsProgression(string userId) 
    { 
     _userId = userId; 
    } 
} 
// Immutable Step Object 
public class Step1 
{ 
    public string input1 { get; } 
    public string input2 { get; } 
    public string input3 { get; } 
} 

Вы инстанцирует StepsProgression на первом этапе, поэтому я полагаю, вы знаете только чьими шагами. Поэтому конструктор устанавливает только идентификатор пользователя. Затем, когда пользователь заполняет входы step1 и клики Далее, тогда вы создаете новый (неизменный) объект Step и устанавливаете его на step1. Если пользователь нажимает Назад, что-то изменит с шага 1 и снова нажмет Далее, затем вы снова создаете новый объект Step1 и назначаете его StepsProgression.

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

Отредактировано Реализация: Я понимаю, что StepsProgressions содержит динамического набор шагов, которые вы определяете непосредственно перед созданием StepsProgression. Тогда если вы знаете stepTypes заранее я хотел бы изменить свою реализацию следующим образом:

public class StepsProgression 
{ 
    private readonly string _userId; 
    private readonly IStepProgressionBuilder _builder = new StepProgressionBuilder(); 
    public IEnumerable<IStep> Steps { get; set; } 

    public StepsProgression(string userId, IEnumerable<string> stepTypes) 
    { 
     _userId = userId; 
     foreach (var step in stepTypes) // foreach smells here but you got the point 
     { 
      _builder.AddConcreteStep(step) // step = "Step1" for instance. 
     } 
     Steps = _builder.Build(); 
    } 
} 
// Immutable Step Object 
public class Step1 : IStep 
{ 
    public string input1 { get; } 
    public string input2 { get; } 
    public string input3 { get; } 
} 
// Builder Pattern with Fluent Methods 
public interface IStepProgressionBuilder 
{ 
    // stepType = "step1" for instance. You have concrete Step1 class, so you return it. 
    // Start with a switch, then you refactor. (May involve some reflection) 
    void AddConcreteStep(string stepType); 
    IEnumerable<IStep> Build(); 
} 

Опять вы можете использовать один общий класс Step, но тогда ваш строитель должен shomehow строить шаг, принимая каждый данные шаг должен содержать. Затем это становится кодовым кодом, если ваши шаги могут иметь более 3 свойств.Вот почему я предпочитаю иметь конкретные классы Step, чтобы я мог построить его как целый набор данных.

+0

Благодарим за сообщение. Мы спросили экспертов домена, и шаги в порядке, но шаги, не связанные с пользовательским интерфейсом. Мне понравился ваш пример, но я бы хотел иметь экземпляры Шагов при создании StepsProgression. Поскольку шаг прогрессии может иметь много разных шагов, так что одна StepsProgression может полностью отличаться от другой. И мне нужен способ получить доступ ко всем данным со всех шагов в One StepsProgression, поэтому требуется StepsData. – Clickbeetle

+0

Я понимаю, что ваш StepsProgression содержит «динамический» набор шагов, который может отличаться от того, который отличается от мастера формы, и вы хотите использовать общий класс StepsProgression. Если я не ошибаюсь, я отредактировал решение по вашим потребностям. – stratovarius

0

Итак, я решил сделать StepsData объектом Value. Это дает мне преимущество защиты от записи за пределами StepsProgression.

я могу передать StepsData вне StepsProgression только для чтения без забот, потому что если кто-то за пределами будет называть сеттер на StepsData, новый объект будет возвращен. А за пределами StepsProgression вы не можете переписать оригинал StepsData. Так что, даже если кто-то называет сеттер, оригинал StepsData в StepsProgression по-прежнему не изменился.

Смежные вопросы