Скажем, у нас есть совокупный корневой объект Порядка типа, который связывает строки порядка и клиенты. Когда я думаю об объекте порядка, более естественно осмыслять его как не определяемый без идентификатора. Порядок без идентификатора, кажется, лучше представлен как запрос порядка, чем порядок.
Для добавления порядка к репозиторию я обычно вижу, что люди инстанцируют порядка без идентификатора и затем имеют репозиторий, завершенный объект:
class OrderRepository
{
void Add(Order order)
{
// Insert order into db and populate Id of new order
}
}
То, что мне нравится приблизительно этот подход, - то, что Вы добавляете экземпляр Порядка к OrderRepository. Это имеет большой смысл. Однако экземпляр порядка не имеет идентификатора, и в объеме потребителя репозитория, он все еще не имеет никакого смысла мне, что порядок не имеет идентификатора. Я мог определить OrderRequest, чтобы быть экземпляром порядка и добавить, что в репозиторий, но это испытывает желание получать яблоко из апельсина и затем добавлять его к списку апельсинов.
С другой стороны, я также видел этот подход:
class OrderRepository
{
Order AddOrder(Customer customer)
// It might be better to call this CreateOrder
{
// Insert record into db and return a new instance of Order
}
}
То, что мне нравится приблизительно этот подход, - то, что порядок не определен без идентификатора. Репозиторий может создать запись базы данных и собрать все обязательные поля прежде, чем создать и возвратить экземпляр порядка. Какие запахи здесь то, что Вы никогда на самом деле добавляете экземпляр порядка в репозиторий.
Так или иначе работы, таким образом, мой вопрос: я должен жить с одной из этих двух интерпретаций, или существует ли лучшая практика для моделирования вставки?
Я нашел этот ответ, который подобен, но для объектов значения: как я должен добавить объект в набор, сохраняемый совокупным корнем. Когда дело доходит до объекта значения нет никакого беспорядка, но мой вопрос касается объекта идентификационными данными, полученными из внешнего источника (Автоматически сгенерированный идентификатор Базы данных).
Я хотел бы начать с помощью второго подхода Отказ Не только это кажется противоположностями, он также нарушает несколько хороших принципов проектирования, таких как разделение командования и принцип , как минимум сюрприз .
Остальные параметры зависят от логики домена. Если логика домена определяет, что порядок без идентификатора не имеет смысла, идентификатор является обязательным инвариантным порядком, и мы должны моделировать его так:
public class Order
{
private readonly int id;
public Order(int id)
{
// consider a Guard Clause here if you have constraints on the ID
this.id = id;
}
}
Обратите внимание, что, путем размещения поля
как Readonly
Мы сделали это инвариантным. Нет никакого способа изменить его для данного экземпляра порядка. Это идеально подходит с дизайном доменов объект .
Вы можете дополнительно привести к обеспечению логике домена, поместив охранник в конструктор, чтобы идентификатор был отрицательным или ноль.
К настоящему времени вам, вероятно, вам интересно, как это, возможно, будет работать с автоматически сгенерированными идентификаторами из базы данных. Ну, это не так.
Нет хорошего способа убедиться, что прилагаемый идентификатор еще не используется.
Это оставляет вас двумя вариантами:
Во многих случаях создание нового порядка является бизнес-операция, которая нуждается в конкретном моделировании в любом случае, поэтому я не вижу проблем с этим различием. Хотя порядок и заказ могут быть семантически очень похожими, они даже не должны быть связаны в иерархии типа.
Я мог бы даже пойти так далеко, как сказать, что они не должны быть связаны , потому что заказа представляет собой объект значение , тогда как порядок является объектом .
Если этот подход принят, метод дополнения должен возвращать экземпляр заказа (или, по меньшей мере, идентификатор), потому что в противном случае мы не можем знать идентификатор того, что мы только что создали. Это приводит нас к нарушению CQS, поэтому я склонен к , предпочитаю GUID для идентификаторов объектов .