2013-09-27 3 views
0
public class ProjectType : Entity 
{ 
    public ProjectType(Guid id,string name) 
    { 
    Id=id; 
    Name=name; 
    } 

    public virtual string Id {get;private set;} 
    public virtual string Name {get;private set;} 
} 

public class Project : Entity 
{ 
    public Project(Guid id, ProjectType projectType) 
    { 
    Id = id; 
    ProjectType = projectType; 
    } 

    private IList<Task> _tasks = new List<Task>(); 
    public ProjectType {get;private set;} 
    public IEnumerable<Task> Tasks 
    { 
    get{ 
     return _tasks; 
    } 
    } 

    public void AddTask(Task task) 
    { 
    // some business logic for this.ProjectType 
    task.SetProject(this); 
    _tasks.Add(task); 
    } 

    public void RemoveTask(Task task) 
    { 
    _tasks.Remove(task); 
    } 
} 

public class Task : Entity 
{ 
    public Task(Guid taskId,Project project) 
    { 
    Id = taskId, 
    Project = project; 
    } 

    public Project Project {get;private set;} 
    public Task ParentTask {get;private set;} 

    private IList<Task> _subTasks = new List<Task>(); 

    public IEnumerable<Task> SubTasks 
    { 
    get{ 
     return _subTasks; 
    } 
    } 

    public void AddSubTask(Task task) 
    { 
    // some business logic for Project.ProjectType 
    task.SetProject(this.Project); 
    task.ParentTask = this; 
    _subTasks.Add(task); 
    } 

    public void RemoveSubTask(Task task) 
    { 
    _subTasks.Remove(task); 
    } 

    internal void SetProject(Project project) 
    { 
    Project = project; 
    } 
} 

Мои вопросы:ддд, совокупный дизайн корень

  1. Является ли проект совокупный корень?
  2. Является ли агрегированный корень задачи?
  3. Должен ли AddTask, RemoveTask быть частью проекта?
  4. Должен ли AddSubTask, RemoveSubTask быть частью задачи?

ответ

2

Ответ зависит от инвариантов, которые вы (на самом деле эксперты домена) хотите защитить.

Проект представляет собой совокупность, а Task - это локальная сущность, когда addTask и вы хотите защитить некоторые инварианты (например, ваш комментарий «// какая-то бизнес-логика для этого .ProjectType») в одной транзакции (что означает, что это ограничение не должно быть сломанный в любое время). Поэтому addTask/removeTask и даже addSubTask/removeSubTask следует добавить в Project. Если есть только один пользователь (например, менеджер проектов), это нормально, но если многие пользователи (например, правообладатель) хотят изменить свою задачу, это может привести к частым одновременным сбоям, что делает приложение непригодным.

Возможно, вас заинтересовало Vernon‘s famous article about aggregate. Например, пример, который он предположил, довольно похож на ваш случай.

UPDATE

Я имею в виду, что большой агрегат вызывает одновременный сбой ненужным. Предполагая, что Project является агрегированным, а Task - это локальные объекты, то все задачи добавления/удаления и изменения могут выполняться только через Project. Предположим, что я являюсь правопреемником задачи 1 Project1, и вы являетесь помощником Task2 Project1, но мы не можем одновременно обновлять описание задачи для выполнения Project1 (одно успешное, а другое - неудачное сбой в параллелизме). Эта проблема более серьезная, если есть большой Проект и много задач (поэтому потенциально много правопреемников). С другой стороны, если приложение предназначено только для менеджера проектов, то большой агрегат не является проблемой, потому что редко два менеджера проекта меняют один проект одновременно.

UPDATE2

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

Если задача представляет собой совокупность, то только Task1 блокируется, когда кто-то хочет ее отредактировать, потенциальная конкуренция низкая (если кто-то в свое время хочет отредактировать Task2, отлично, просто сделайте это, не проблема параллелизма).

Но если проект является совокупностью, каждый хочет отредактировать Task1, необходимо заблокировать проект, и, следовательно, другие хотят отредактировать Task2 (также необходимо заблокировать проект), обнаруживает сбой параллелизма или должен ждать. Это может быть проблемой юзабилити, люди раздражаются, когда часто не удалось сделать нерелевантную проблему (с точки зрения пользователя, почему я не могу редактировать Task2, когда кто-то редактирует Task1?).

Решение, упомянутое в статье Вернона, заключается в использовании меньшего агрегата. Это улучшает пропускную способность и масштабируемость, но также увеличивает сложность (инварианты, которые защищены транзакцией Project, теперь необходимо защищать в последовательном порядке согласованности, другими словами, не защищенными в любое время).Я предлагаю вам внимательно изучить инварианты (они действительно необходимы) и сделать ваше решение на основе реальной мысли и масштабируемости, а не некоторые предвзятые правила, такие как «Меньший агрегат лучше». Приветствия.

+0

Я не понимаю эту строку: «Если есть только один пользователь (например, менеджер проектов), это нормально, но если многие пользователи (например, правопреемники) хотят изменить свою задачу, это может привести к частым параллельным сбоям, делает приложение непригодным ». – oguzh4n

+0

@ oguzh4n Извините, мой плохой английский :(Смотрите мое обновление, и вы можете получить больше плюсов и минусов небольшого агрегата в статье Вернона (см. Ссылку) – Hippoom

+0

спасибо за обновление, задача может редактировать со многими пользователями одновременно, поэтому я hink использовать оптимистичный параллелизм, но вы говорите «параллелизм в проекте», как я могу решить эту проблему параллелизма? – oguzh4n

1

1 + 2. Может ли проект жить самостоятельно, без какой-либо зависимости с другим сущностью, имеет ли он собственный независимый жизненный цикл? Да. Это совокупность. Может ли задание жить без какой-либо другой зависимости? Имеет ли смысл иметь задачу над своим проектом без проекта? Кажется, это не так. Это не совокупность (root). Только проект имеет независимый жизненный цикл, задачи нет.

3 + 4. Поскольку задача зависит от проекта, имеет смысл добавить/удалить/просто задачи CRUD в проекте.

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

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