2013-06-04 4 views
5

Мы вначале пытаемся принять проект, управляемый доменом, в нашем проекте. Проблема у меня связана с ассоциациями между сущностями. Как вы их делаете правильно?Правильный способ реализации ассоциаций в DDD?

Скажите, у меня есть объекты Employee и Contract, простая ассоциация «один-ко-многим». Как мне его моделировать?

Вариант 1: Совокупный.

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

Вариант 2: Получение контрактов работника, используя хранилище (например, ContractRepository.GetContractsForEmployee()) и добавление EmployeeId свойства Contract класса.

Задача: трудно сделать любую бизнес-логику сущностью. Я хотел бы иметь метод, скажем, Employee.Dismiss(), но ему также необходимо будет обновить контракт сотрудника. Это означает, что мне нужно будет поставить эту логику в службу. Проблема в том, что я не могу придумать много логики, работающей только на Employee, и, таким образом, модель станет несколько анемичной, с большинством логических внутренних сервисов.

Как вы справляетесь с этими проблемами в DDD?

+1

Как только вы думаете о «простой ассоциации один-ко-многим», вы не используете DDD, вы создаете схему схемы базы данных. Связь между сущностями должна быть поведением. Работник не может уволить себя, он должен быть уволен (другим органом, который имеет право сделать это). Вариант 2 является правильным. Вам не нужно придумывать много действий для Entity. Если объект домена очень прост в реальном бизнесе, моделируйте его таким образом. Это важно, как домен определяет концепцию (семантику), а не то, сколько методов имеет объект. – MikeSW

+0

MikeSW правильный. Очень важным аспектом DDD является вездесущий язык. То, как вы говорите о домене, ДОЛЖНО быть тем, как эксперт домена говорит о Домене, иначе код становится неудобным и неинтуитивным. Это звучит тривиально, но если вы получите это право, то Entities начнут предлагать поведение. например Employee.Resign(); Contract.Terminate(); – Asher

ответ

2

Это просто мое взятие на себя ... без знания вашего домена.

Во-первых, here - хороший ресурс для чтения (часть об Агрегатах и ​​Корнях).

В терминологии DDD, Employee и Contract оба лица (потому что они оба имеют идентичность).

«Заполнители провести границу вокруг одного или нескольких лиц, а также:. каждый агрегат имеет корень Entity, который является единственным членом Совокупности, что любой объект вне агрегата разрешается содержать ссылку."

Возникает вопрос: делать Employee и Contract, образуют совокупности с Employee является корневым объектом Очевидно, что нет, потому что другие субъекты домена также могут иметь ссылку на contract и подрядные идентификаторы являются глобально уникальными, не? . только в пределах Customer

Таким образом, принимая во внимание эти правила, Employee и Contract оба агрегатных корней

. Тогда: «только агрегатные корни могут быть получены непосредственно с запросами; так что это означает, что мы должны иметь хранилище на агрегат корня.»

Так что в данном случае мы имеем EmployeeRepository и ContractRepository.

Принимая все это во внимание, я не хотел бы добавить связь между сотрудников и контрактов в модели домена, но относиться к ним отдельно. В конце концов, если вам нужен Employee, вам необязательно понадобится его contracts, они оба разные аспекты.

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

Если вы также определяете объект Company, то увольнение сотрудника может быть заданием этого объекта.

0

Вам нужно найти свои истинные инварианты.

Здесь может существовать инвариант, такой как: вы не можете уволить Employee, который уже был уволен.

Если это единственный реальный инвариант, то вы можете сделать один агрегат Employee, который будет иметь только идентификаторы связанных контрактов.

Contract будет другим агрегатом (при необходимости).

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

1

Мы недавно попали в подход DDD. Если бы я это сделать, я бы следующее (атрибуты упрощены для краткости):

public class Employee() { 

    String name; 
    Set<ContractNumber> contracts; 

    public void addContract(ContractNumber contractNumber) { 
     this.contracts.add(contractNumber); 
    } 

} 

public class Contract() { 
    ContractNumber contractNumber; 
    Date effectiveDate; 
} 

public class ContractNumber() { 
    String contractNumber; 
} 

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

Как обсуждалось в других ответах, будут созданы хранилища как для Работника, так и для Контракта.

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