Как определить предварительные условия для внешнего состояния, используя кодовые контракты?
Как мне поставить предварительное условие на Invoke
метод в следующем интерфейсе, заявив, что объект, обозначенный ObjectId
должен существовать?
interface IDeleteObjectCommand {
Guid ObjectId { get; }
void Invoke();
}
Попытка № 1
У меня уже есть команда под названием IObjectExistsCommand
который может быть использован для определения, существуют ли объекты. Эти команды могут быть созданы с помощью IObjectExistsCommandFactory
, Я думал о том, чтобы сделать следующее, но это добавляет нежелательный шум в интерфейс команды (IMO):
interface IDeleteObjectCommand {
IObjectExistsCommandFactory ObjectExistsCommandFactory { get; }
Guid ObjectId { get; }
// Contract.Requires(ObjectExistsCommandFactory.Create(ObjectId).Invoke());
void Invoke();
}
Попытка № 2
Аналогично выше, кроме использования ServiceLocator
, Нежелательно по понятным причинам, но чище:
interface IDeleteObjectCommand {
Guid ObjectId { get; }
// Contract.Requires(ServiceLocator.Get<ObjectExistsCommandFactory>().Create(ObjectId).Invoke());
void Invoke();
}
РЕДАКТИРОВАТЬ: Точно так же, как бы вы определили постусловия на внешнее состояние? Т.е. говоря, что этот метод приводит к существованию нового файла.
2 ответа
Я думаю, что это плохая идея. Это один из тех контрактов, на который распространяется условие гонки, и мне они не нравятся (два абонента проверяют, что контракт выполнен, затем один выигрывает гонку, чтобы удалить объект, а затем второй получает исключение нарушения контракта, когда он пытается удалить объект).
Создайте исключение, если удаляемый объект не существует.
Я решил создать "Предварительные условия" enum
который определяет внешние предварительные условия. Затем я определил отдельный метод на интерфейсе, который возвращает enum
, таким образом, намекает на то, что биты внешнего состояния являются недействительными:
interface IDeleteObjectCommand {
Guid ObjectId { get; }
DeleteObjectPreconditions? GetImpediments();
// Contract.Requires(!this.GetImpediments().HasValue);
void Invoke();
}
enum DeleteObjectPreconditions { ObjectExists, ObjectUnlocked };
Я полностью помешан на этом? Единственным недостатком этого, конечно, является то, что у пользователей нет доказуемого средства для того, чтобы когда-либо удовлетворить предварительные условия...
РЕДАКТИРОВАТЬ: Я на самом деле предпочитаю метод определения местоположения службы по сравнению с этим. По крайней мере, с таким подходом пользователи могут доказать, что предварительные условия выполняются через контрактный (хотя и расположенный на службе) интерфейс.
РЕДАКТИРОВАТЬ 2: Это поднимает интересный вопрос... как бы вы определили постусловия на внешнее состояние?