2015-06-03 2 views
1

Рассмотрим следующий сценарий:DDD логика и Постоянство Незнание

public class Document 
{ 
    private ISet<User> sharedWith; 

    public Document(string name) 
    { 
    this.sharedWith = new HashSet<User>(); 
    this.Name = name; 
    } 

    public string Name { get; private set; } 

    public IEnumerable<User> SharedWith 
    { 
    get 
    {  
     return this.sharedWith; 
    } 
    } 

    public void ShareWith(User user) 
    { 
    if (this.SharedWith.Contains(user)) 
    {  
     throw new Exception("This document is already shared with that user."); 
    } 

    this.sharedWith.Add(user); 
    } 
} 
  • Documents может использоваться совместно с User
  • При совместном использовании документа с пользователем, если документ уже совместно с этим пользователем, выбросить исключение.
  • Документы могут использоваться совместно с 10 тысячами пользователей.

Очевидно, что это не очень хорошо масштабируется, из-за необходимости проверки SharedWith для пользователя существования, в результате ОРМ ленив загрузкой всей коллекции в памяти. I может выполнить проверку наличия в службе приложения, но я рассматриваю эту логику домена, и поэтому для меня имеет смысл, что я храню ее в классе Document.

Я не могу понять, как это должно быть сделано с DDD? И что, если я не смогу использовать ORM, как это сделать?

Я предполагаю, что я должен иметь документ Aggregate и пользователя агрегатный?

Я просмотрел различные ресурсы DDD (я еще не читал книгу), но я не могу найти ответ на этот конкретный сценарий.

+0

этот тип логики может/должен принадлежать в рамках службы домена. просто еще одна тактическая схема борьбы с такими вещами. у вашего репо может быть простой метод, возвращающий bool на то, был ли док совместно с конкретным пользователем – Marco

+0

@Marco, тогда я не понял, что логика должна идти в самих классах домена? Разве это не то, что я назвал логикой домена? – Jeff

+0

граница согласованности, которую обеспечивает совокупность, является ее инвариантами. действительно ли ваши бизнес-пользователи * действительно говорят, что это бизнес-правило или это то, что вы придумали сами? – Marco

ответ

2

это было быстро сделано так, что это не идеальный, но вы получите его суть:

public class User { public Guid UserId { get; set; } } 

public class Document 
{ 
    public string Name { get; private set; } 

    private ICollection<User> sharedWith = new List<User>(); 

    private DateTime? publishedOn; 

    public Document(string name) 
    { 
     if (string.IsNullOrWhiteSpace(name)) 
     { 
      throw new ArgumentException("Name is required"); 
     } 

     this.Name = name; 
    } 

    public void Publish() 
    { 
     if (this.publishedOn.HasValue == false) 
     { 
      this.publishedOn = DateTime.UtcNow; 
     } 
    } 

    public void SharedWith(User user) 
    { 
     if (this.publishedOn.HasValue == false) 
     { 
      throw new InvalidOperationException("Document must be published for sharing is allowed."); 
     } 

     sharedWith.Add(user); 
    } 
} 

public interface IDocumentRepository 
{ 
    Document documentOfId(Guid id); 

    bool IsAlreadySharedWith(Guid documentId, Guid userId); 
} 

public interface IUseRepository 
{ 
    User userOfId(Guid id); 
} 

public class ShareDocumentService 
{ 
    private readonly IUseRepository userRepository; 
    private readonly IDocumentRepository documentRepository; 

    public void ShareWith(Guid userId, Guid documentId) 
    { 
     if (documentRepository.IsAlreadySharedWith(documentId, userId)) 
      throw new InvalidOperationException("Document has already been shared with user."); 

     User user = userRepository.userOfId(userId); 

     Document doc = documentRepository.documentOfId(documentId); 

     doc.SharedWith(user); 
    } 
} 
+0

Комментарии не предназначены для расширенного обсуждения; этот разговор был [перемещен в чат] (http://chat.stackoverflow.com/rooms/79562/discussion-on-answer-by-marco-ddd-logic-and-persistence-ignorance). – Taryn

+0

Так много, чтобы измениться, и у меня есть тесты для всего, так что это похоже на работу в 4 раза! – Jeff

+0

Теперь, когда у меня больше нет ссылок между объектами, как мне сопоставить это с отношениями в моем SQL-db? Извините за тащить это: P – Jeff

1

Я полагаю, что если бы вы моделировали это в мире, основанном на бумаге/актере, тогда у кого-то была бы задача сортировки, у кого есть доступ к тому или иному документу (документам), и это, вероятно, будет опираться на какой-то бумажный артефакт. Чтобы получить доступ к документу, вам необходимо заполнить форму запроса документа, которая может пройти процесс утверждения.

Эта форма в мире, основанном на бумаге, станет связующим звеном «многие-ко-многим», который станет ключом к доступу пользователей к защищенным документам. Это сделало бы User, Document и DocumentRequestForm тремя отдельными объектами.

+0

В моем случае это так же просто, как указано в вопросе. Однако я не вижу, как разделение его на «DocumentRequestForm» решает необходимость загрузки коллекции в память? – Jeff

+0

@Jeff Я действительно сделаю его «совокупным корнем DocumentSharing», но идея такая же. Это решает необходимость загружать коллекцию, потому что «Документ» не имеет прямой ссылки на «Пользователи», в которых он был совместно использован. Все находится в 'DocumentSharing', который, поскольку Aggregate Root имеет свой собственный репозиторий, позволяет вам узнать, существует ли данный обмен уже существующим. Кроме того, ссылки моделируются как ссылки на идентификаторы (которые рекомендуются для связей с агрегированием для агрегирования) вместо полных ссылок на объекты. – guillaume31

+0

@ guillaume31 Я не смог найти конкретный пример совокупного корня, не могли бы вы дать небольшой пример того, как агрегат 'DocumentSharing'? Похоже на то, что мне нужно. – Jeff

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