Нет, по моему мнению, доменные объекты никогда не должны быть недействительными, даже временно. Проблема в том, что если вы разрешите домену быть недействительным, как вы описали в своем вопросе, становится сложно вводить новые правила по мере роста сложности. Например, вы разрешаете объекту быть недействительным из-за какого-либо атрибута, предполагая, что он будет проверен позже. Но до того, как это произойдет, кто-то добавляет другое правило, которое изменяет свой результат в соответствии с тем же атрибутом - как узнать, правильно ли ведет себя правило? Вы не Поверьте мне, это происходит довольно часто в нетривиальных областях.
Другая причина недопустимости состояния и его недопущения заключается в том, что в определенных сценариях это может привести к проблемам с ORM - лично я видел проблему, связанную с кешем NHibernate и недействительными суб-объектами, которые каким-то образом все еще оставались в кеше, я могу не помню каких-либо конкретных подробностей.
Техника, которую я склонен использовать, основывается на правилах валидации и результатах валидации. Короче говоря, большинство методов для сущностей реализовано следующим образом (C #, если вы не возражаете):
public virtual void ChangeClaimEventDate(DateTimeOffset newDate)
{
var operationResult = ValidatorOf<Claim>
.Validate()
.WithCriticalRuleOf<EventDateFallsIntoPolicyCoverage>().WithParam(newDate)
.WithCriticalRuleOf<EventDateFallsIntoInsuredCoverage>().WithParam(newDate)
.WithCriticalRuleOf<PerformedServicesAreAvailableOnEventDate>().WithParam(newDate)
.WithCriticalRuleOf<EventDateCannotBeChangedForBilledClaim>().WithParam(newDate)
.ForOperation(this);
if (operationResult.OperationFailed)
{
throw new InvalidBusinessOperation(operationResult);
}
SomeDate = newDate;
}
Самым важным в этом коде является то, что некоторые правила проверки проверяются еще до изменения объекта. В этом примере показано использование наборов результатов, так как очень часто мне нужно предоставить информацию о проверке, даже если она прошла успешно (другими словами, у меня есть проверки, которые не пройдены, и информация о них должна быть показана пользователю; однако сущности домена все еще действительны .
OperationResultSet
и ValidatorOf
- довольно простые классы инфраструктуры, которые позволяют легко добавлять новые валидаторы с помощью свободного интерфейса. Валидаторы реализованы в виде классов, реализующих интерфейс IValidator
, который позволяет реализовать довольно сложные правила проверки, а также проще тестировать их по отдельности.
Моя точка зрения заключается в том, что проверка должна выполняться до того, как будут внесены изменения в сущности домена - с правильным соглашением и некоторой инфраструктурой это даже упрощает структуру кода.
Изменить примечание: из-за некоторых критических голосов для этого ответа я решил изменить пример кода, который выдает исключение вместо возврата результатов. Несмотря на то, что я все еще верю, что это подход к моим сценариям, я согласен, что без указания полного контекста это может ввести в заблуждение - исключения должны быть действительно первым вариантом, и для выбора альтернатив должны существовать дополнительные факторы.