我正在尝试实现自己的编程语言,而且我正在进行lexing和解析。我差不多完成了,并希望为类不变量,前置条件和后置条件添加原生支持。
public withdraw (d64 amount) : this {
require amount > 0;
require this.balance - amount > this.overdraft;
# method code
d64 newBalance = this.balance - amount;
ensure this.balance == newBalance;
}
您还可以在类的顶部定义类不变性。
class BankAccount {
invariant this.balance > this.overdraft;
# class body
}
这是我的问题:
我自己想一想,我认为在接口中包含不变性或后置条件并不合理,但我并没有真正看到前提条件的问题。
可以在下面的抽象和接口方法中包含前置条件和后置条件。
public interface BankAccount {
public withdraw (d64 amount) : this {
require amount > 0;
require this.balance - amount > this.overdraft;
# no other statements (implementation)
d64 newBalance = this.balance - amount;
ensure this.balance == newBalance;
}
}
答案 0 :(得分:0)
这实际上取决于您的界面是有状态还是无状态。包含接口方法的前置和/或后置条件可能非常好。事实上,我们一直这样做。无论何时创建一个javadoc(或任何其他工具),您都要创建一个合同。否则,你怎么测试什么?重要的是要意识到测试驱动开发和按合同设计有很多共同之处。定义合同对于正确的tdd至关重要 - 您首先要设计一个接口并为其创建非正式合同(使用人类可读的语言)。然后,您编写测试以确保合同得到满足。如果我们遵循tdd classicists(https://www.thoughtworks.com/insights/blog/mockists-are-dead-long-live-classicists),我们总是针对合同编写测试。
现在,更具体一点。如果接口是有状态的,我们可以根据其他方法轻松表达其不变量。我们以java List
接口为例:
如果你仔细阅读javadoc,你会发现有很多不变量。例如,add
方法具有以下合同:
前提条件:元素不能为空(如果列表不支持它 - 在我看来,这是一种设计气味,但让我们把它放在一边 现在)
后置条件:保留排序,即其他排序 元素无法更改
由于List
接口肯定是有状态的,我们可以使用查询方法来推断列表的状态,例如get
,sublist
等。因此,您可以表达所有不变量在接口的方法上。
如果接口是无状态的,例如Calculator
,我们也定义了一个契约,但它的不变量不包含任何状态。因此,例如,sum
方法可以具有以下合同:
int sum(int a, int b)
Preconditions: a and b are integers (which is automatically guaranteed by static type checking in Java)
Postconditions: the result is an integer (again - type safety) which is equal to a + b
我们的Calculator
是无状态接口,因此我们的不变量中不包含任何状态。
现在,让我们回到您的BankAccount
示例:
您描述的方式,BankAccount
绝对是一个有状态的界面。实际上,它是我们称之为Entity
(在域驱动设计方面)的模型示例。因此,BankAccount
拥有它的生命周期,它是状态,并且可以(并且将会)在其生命周期内发生变化。因此,根据班级的状态方法表达合同是完全正确的。您需要做的就是将amount
,balance
和overdraft
移动到界面的顶部,作为属性(如果您的语言支持它)或方法 - 它不会'真的很重要。重要的是amount
,balance
和overdraft
现在是您界面的一部分,并形成界面的无所不在的语言 。这些方法/属性是整个BankAccount
接口的组成部分 - 这意味着它们可以作为接口合同的一部分。
前段时间我实现了一个非常简单的Java契约原型,实现为面向方面编程支持的注释集。我试图实现与你类似的目标 - 将合同与语言结合起来,使其更加正式。这只是一个非常简单的原型,但我认为它很好地表达了这个想法。如果你有兴趣 - 我应该很快将它上传到github(我到目前为止大部分时间都在使用bitbucket)。