Неизменность в совокупности дочерних объектов - PullRequest
0 голосов
/ 31 октября 2019

Я начал использовать принципы проектирования на основе домена, но в настоящее время застрял с конкретной проблемой.

У меня есть Агрегат, который имеет несколько слоев вложенных дочерних объектов, как показано ниже:

public class Aggregate: Entity<AggregateId>, IAggregateRoot {
    private readonly List<ChildOne> childOnes;
}

public class ChildOne: Entity<ChildOneId> {
    public string ChildOneValue1;
    public string ChildOneValue2;
    public string ChildOneValue3;
    private readonly List<ChildTwo> childTwos;
}

public class ChildTwo: Entity<ChildTwoId> {
    public string ChildTwoValue1;
    public string ChildTwoValue2;
    public string ChildTwoValue3;
}

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

public interface IDomainService {
    public IEnumerable<INotification> Analyze(Aggregate aggregate);
}

Однако я не могу вернуть сущности такими, какие они есть, поскольку это нарушило бы принцип неизменности.

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

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

Есть предложения о том, как к этому подойти?

Ответы [ 2 ]

0 голосов
/ 02 ноября 2019

Однако я не могу вернуть сущности такими, какие они есть, поскольку это нарушило бы принцип неизменности.

Сущности не должны быть неизменными. Это единственный ценностный объект, который неизменен в тактическом дизайне доменного дизайна.

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

0 голосов
/ 01 ноября 2019

Любые предложения о том, как подойти к этому?

Есть несколько возможностей.

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

public interface IDomainService {
    public IEnumerable<INotification> Analyze(IEnumerable<DomainValue> values);
}

Если вы вспомните шаблон Visitor из книги «Банды четырех», оночень похожая идея.

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

public interface IDomainService {
    public void OnAnalyze(DomainValue value);
    public IEnumerable<INotification> Notifications();
}

Другая возможность состоит в том, чтобы спроектировать агрегат для работы в качестве коллекции

public class Aggregate {
    // ...

    public IEnumerable<DomainValue> YourCleverNameHere();
}

Для случаев использования, когда вы не меняете состояниеагрегат, просто оставьте агрегат вне него и работайте напрямую с неизменяемым в памяти представлением текущего состояния.

...