如何使用代码合同定义外部状态的前置条件?

3

如何在下面的接口中对Invoke方法放置前提条件,指定由ObjectId表示的对象必须存在?

interface IDeleteObjectCommand {
   Guid ObjectId { get; }
   void Invoke();
}

尝试 #1

我已经有一个名为 IObjectExistsCommand 的命令,可以用于确定对象是否存在。这些命令可以通过 IObjectExistsCommandFactory 实例化。我考虑过以下做法,但这会给命令的接口增加不必要的噪音(在我看来):

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();
}
编辑:同样,你如何定义外在状态的后置条件?即指该方法会导致新文件的存在。

在接口中添加一个 Object Object { get; } 属性,该属性返回对象本身而不是 ID? - Rob
有趣的问题。我看不到你有任何其他选择,除了提供通过界面本身进行检查的手段(尝试#1),或提供静态手段(尝试#2)。但我可能是错的。 - Rob
嗯,我不确定预先加载实体在所有情况下都是可行的妥协方案。不过还是谢谢你的建议。 - Lawrence Wagerfield
在我看来,这似乎更像是一个断言而不是合同检查。我认为合同检查将涵盖ObjectId不是Guid.Empty,从而使您有信心继续进行。 - Davin Tryon
问题在于,即使用户遵守了方法的所有前置条件,他们仍然可能收到异常。我认为这个想法是要使方法确定性,以便用户可以100%确定在遵守前置条件时不会抛出任何异常。 - Lawrence Wagerfield
关于这个,我觉得有点不对劲。如果调用者可以通过超自然的确定性验证GUID是否有效,则他们应该能够调用某个对象或静态类上的具体删除方法,而不是在抽象命令接口上调用Invoke。也许您可以告诉我们更多关于这个设计的信息,以便我们可以看到其他选择? - Jeffrey L Whitledge
2个回答

1

我认为这是一个不好的想法。这是那些容易出现竞态条件的合约之一,而我不喜欢那些(两个调用者都验证该合约是否满足,然后一个赢得删除对象的比赛,第二个尝试删除对象时会出现合约违规异常)。

如果要删除的对象不存在,则抛出异常。


我同意你所说的,但是这不是与不应该依赖异常来控制应用程序流程的概念相矛盾吗?此外,确保资源上存在锁定(通过TransactionScope或其他机制)的责任不是由调用方承担吗? - Lawrence Wagerfield
我认为这正是异常存在的原因。另一个更明显的情况是:想象一个需要 Requires(File.Exists(someArg)) 的函数 - 调用者绝对无法保证这一点,因为它依赖于第三方状态,而调用者无法控制,所以在失败时抛出异常而不是使用 Requires 是完美的情况。 - porges

0

我决定创建一个“Preconditions”枚举,用于定义外部前提条件。然后我在接口上定义了一个单独的方法,该方法返回枚举,从而提示哪些外部状态位无效:

interface IDeleteObjectCommand {
   Guid ObjectId { get; }
   DeleteObjectPreconditions? GetImpediments();

   // Contract.Requires(!this.GetImpediments().HasValue);
   void Invoke();
}

enum DeleteObjectPreconditions { ObjectExists, ObjectUnlocked };

我这样做是不是完全疯了?当然,唯一的缺点是用户没有可证明的手段来满足先决条件...

编辑:实际上,我更喜欢服务位置方法。至少通过这种方法,用户能够通过合同(虽然是服务定位)接口证明先决条件得到满足。

编辑2:这提出了一个有趣的问题...如何定义外在状态的后置条件?


1
当然,这唯一的缺点就是用户没有可证明的手段来满足前提条件...所以唯一的缺点就是它毫无意义?听起来对我来说是一个很大的"唯一"缺点。 - jason
+1 我认为这只是绝望引发的短暂疯狂,我实际上不会采用这个解决方案 :) - Lawrence Wagerfield
如果你无法100%满足合同,那么它们就不应该是合同。 :) - porges
由于外部状态可以被其他人随时修改,这是否意味着我们应该避免在这些状态上放置先决条件/后置条件?例如,“方法X的先决条件是文件必须存在”。 - Lawrence Wagerfield

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接