通过带有断言的契约进行部分设计
我想就部分实施合同设计的想法征求一些意见。 目标是添加到不提供轻量版本契约(仅不变量和后置条件)的语言,而无需外部库。
我的示例是用 Java 编写的,但我认为这个想法对于许多 OO 语言都很好。
我们有一个这样的类:
class myClass{
type1 field1;
type2 field2;
public myClass(type1 param1){
//do something
}
public type3 method1(type1 param1, type3 param2){
if (paramsAreNotOk()){
throw new IllegalArgumentException();
}
// do a lot of things
return //do something
}
}
我们以这种方式扩展上面的代码:
class myClass{
type1 field1;
type2 field2;
public myClass(type1 param1){
//do something
assert invariant();
}
public type3 method1(final type1 param1, final type3 param2){
assert invariant();
myClass old;
assert ((old = this.clone()) != null)
if (paramsAreNotOk()){
throw new IllegalArgumentException();
}
//do a lot of things
type3 res = //do something
assert method1_post(old, param1, param2, res);
assert invariant();
return res;
}
protected boolean invariant(){
// states something about myClass and return a boolean
// OR
// uses some assertions on some helping methods
}
protected boolean method1_post(myClass old, type1 param1, type3 param2, type3 res){
// states something about res and about the modifications made on old
// OR
// uses some assertions on some helping methods
}
}
这种方法的局限性:
- 无先决条件。
- 契约不是继承的(但请注意,不变式和后置条件受到保护,并且可以由子类重用)。
- 没有任何检查来确保不变式和后置条件不会修改我们对象的状态,因此存在副作用的风险。
- 合同不是我们文档的明确组成部分。
- 我们需要让每个类都可克隆。
现在,有一些问题:
- 这种方法会以任何方式损害性能吗?我的意思是,如果禁用断言,即使旧的局部变量和 res 局部变量也会被 JIT 编译器删除?
- 您认为这种方法有什么缺点吗?你为什么不在课堂上使用它?
- 你能提出任何改进建议吗?
感谢您的阅读和意见。
I would like to get some opinions on an idea for a partial implementation of design by contract.
The goal is to add to the languages that don't offer it a light version of contracts (invariants and post conditions only) without the need of an external library.
My example is written in Java but I suppose that the idea is good for a lot of OO languages.
We have a class like this:
class myClass{
type1 field1;
type2 field2;
public myClass(type1 param1){
//do something
}
public type3 method1(type1 param1, type3 param2){
if (paramsAreNotOk()){
throw new IllegalArgumentException();
}
// do a lot of things
return //do something
}
}
We extend the code above in this way:
class myClass{
type1 field1;
type2 field2;
public myClass(type1 param1){
//do something
assert invariant();
}
public type3 method1(final type1 param1, final type3 param2){
assert invariant();
myClass old;
assert ((old = this.clone()) != null)
if (paramsAreNotOk()){
throw new IllegalArgumentException();
}
//do a lot of things
type3 res = //do something
assert method1_post(old, param1, param2, res);
assert invariant();
return res;
}
protected boolean invariant(){
// states something about myClass and return a boolean
// OR
// uses some assertions on some helping methods
}
protected boolean method1_post(myClass old, type1 param1, type3 param2, type3 res){
// states something about res and about the modifications made on old
// OR
// uses some assertions on some helping methods
}
}
Limitations of this approach:
- no pre-conditions.
- the contract is not inherited (but please note that invariant and post-conditions are protected and can be reused by a subclass).
- there isn't any check that invariant and post-conditions don't modify the state of our object, hence there is a risk of side effects.
- the contract is not part of our documentation in a clear way.
- we need to make cloneable every class.
Now, some questions:
- does this method hurt the performances in any way? I mean even the old and res local variables are removed by the JIT compiler if assertions are disabled?
- do you see any downside of this approach? Why wouldn't you use this in your classes?
- can you suggest any improvement?
Thank you for your reading and for your opinions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这并不可怕,事实上在你之前其他人已经写过它了。例如,请参阅 Liskov/Guttag 的 Java 中的程序开发,它采用了您的方法不变检查,但称之为repOK()而不是invariant()。
在有限的应用中,它有点起作用。但是,由于合约规范不必像真实代码那样担心“谁在调用谁”的问题,因此产生了很多问题。
我的看法是 DbC 很有趣,如果该语言有它(或者更好的是,像 Python 的函数装饰器之类的东西),或者你有一个像 现代 Jass,然后深入研究。但是用纯 Java 来做是不可行的。也就是说,我正在开发一个不变检查工具,它生成的代码与您这里的代码类似,减去调用链问题(它的工作原理是扩展类以接受知道何时适合进行检查的访问者)。它需要Eclipse,并且有自己的问题(主要是与private和static等坏词有关),但检查机制是纯Java的。
It's not horrible, and in fact it's been written about by others before you. For instance, see Liskov/Guttag's Program Development in Java, which takes your approach to invariant checking, but calls it repOK() rather than invariant().
In a limited application, it kinda-sorta works. But there are a lot of problems that come out of the fact that contract specifications don't have to worry about the sort of "who's calling who" problems that real code does.
My take is that DbC is interesting, and if the language has it (or, even better, something like Python's function decorators), or you have a tool like Modern Jass, then dig in. But doing it in pure Java isn't feasible. That said, I'm working on an invariant checking tool that generates code similar to what you have here, minus the call-chain issues (it works instead by extending the classes to accept a visitor which knows when it's proper to do the check). It requires Eclipse, and has problems of its own (mainly related bad words like private and static), but the checking mechanism is pure Java.
如果您想要 Java 的“契约设计”,您可能想看看(真正的)大佬是如何做的!以下是 Google 最近对“Java 合约”主题的看法:
http ://google-opensource.blogspot.com/2011/02/contracts-for-java.html
现在回答您的两个问题:
因为它的一个缺点是它非常冗长:太冗长以至于使代码几乎不可读。
不要重新发明轮子...
If you want "Design By Contract" for Java, you may want to take a look at how the (really) big guys are doing it! Here's Google's recent take on the subject with "Contracts for Java":
http://google-opensource.blogspot.com/2011/02/contracts-for-java.html
Now to answer two of your questions:
Because one downside is that it is highly verbose: so much verbose as to make the code barely readable.
Don't reinvent the wheel...
我编写的大多数 Java 类都是不可克隆的,因为在 Java 中直接实现
Clonable
并不容易。因此,当不是绝对必要时,我不会实施它。我不想仅仅为了你的方法而这样做。Most Java classes I write are not clonable, because it's not easy to implement
Clonable
right in Java. Therefore I don't implement it when it's not absolutely necessary. I wouldn't want to have to do this just for your approach.