Я хотел бы начать с исключения второго подхода. Это не только кажется нелогичным, но и нарушает несколько хороших принципов проектирования, таких как Разделение команд-запросов и Принцип наименьшего сюрприза .
Остальные параметры зависят от логики домена. Если логика домена диктует, что Заказ без идентификатора не имеет смысла, идентификатор является обязательным инвариантом Заказа, и мы должны смоделировать его так:
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;
}
}
Обратите внимание, что пометив поле id
как readonly
, мы сделали его инвариантом. Мы не можем изменить его для данного экземпляра Order. Это идеально подходит для доменно-управляемого дизайна Entity pattern.
Вы можете дополнительно применить доменную логику, поместив в конструктор предложение Guard, чтобы предотвратить отрицательный или нулевой идентификатор.
К настоящему времени вы, вероятно, задаетесь вопросом, как это будет работать с автоматически сгенерированными идентификаторами из базы данных. Ну, это не так.
Нет хорошего способа убедиться, что предоставленный идентификатор еще не используется.
Это оставляет вам два варианта:
- Измените идентификатор на Guid. Это позволяет любому абоненту предоставить уникальный идентификатор для нового заказа. Однако для этого необходимо использовать Guids в качестве ключей базы данных.
- Измените API, чтобы создание нового заказа не занимало объект Order, а скорее OrderRequest, как вы предложили - OrderRequest может быть практически идентичен классу Order, за исключением идентификатора.
Во многих случаях создание нового заказа является бизнес-операцией, которая в любом случае нуждается в конкретном моделировании, поэтому я не вижу проблем с проведением этого различия. Хотя Order и OrderRequest могут быть семантически очень похожими, они даже не должны быть связаны в иерархии типов.
Я мог бы даже пойти так далеко, чтобы сказать, что они не должны быть связанными, потому что OrderRequest является Value Object , тогда как Order является Entity .
Если выбран такой подход, метод AddOrder должен вернуть экземпляр Order (или, по крайней мере, ID), потому что в противном случае мы не можем знать ID заказа, который мы только что создали. Это возвращает нас к нарушению CQS, поэтому я склонен предпочесть Guids для идентификаторов сущностей .