Skip to content

Commit ec0ae6e

Browse files
authored
Merge pull request lingcoder#280 from xiangflight/master
revision[16] 截止 使用断言进行契约式设计
2 parents d80b671 + 25e2690 commit ec0ae6e

File tree

1 file changed

+15
-23
lines changed

1 file changed

+15
-23
lines changed

docs/book/16-Validating-Your-Code.md

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -198,23 +198,23 @@ JUnit 是 Java 最流行的单元测试框架,但也有其它可以替代的
198198

199199
## 前置条件
200200

201-
前置条件的概念来自于契约式设计(**Design By Contract, DbC**), 利用断言机制实现。我们从Java的断言机制开始来介绍DBC,最后使用谷歌Guava库作为前置条件
201+
前置条件的概念来自于契约式设计(**Design By Contract, DbC**), 利用断言机制实现。我们从 Java 的断言机制开始来介绍 DBC,最后使用谷歌的 Guava 库作为前置条件
202202

203203
#### 断言(Assertions)
204204

205-
断言通过验证在程序执行期间满足某些条件而增加了程序的健壮性。举例,假设在一个对象中有一个数值字段,它表示日历上的月份。这个数字总是介于1-12之间。通过断言检查,如果超出了该范围,则报告错误。如果在方法的内部,则可以使用断言检查参数的有效性。这些是确保程序正确的重要测试,但是它们不能在编译时被检查,并且它们不属于单元测试的范围。
205+
断言通过验证在程序执行期间满足某些条件,从而增加了程序的健壮性。举例,假设在一个对象中有一个数值字段表示日历上的月份。这个数字总是介于 1-12 之间。断言可以检查这个数字,如果超出了该范围,则报告错误。如果在方法的内部,则可以使用断言检查参数的有效性。这些是确保程序正确的重要测试,但是它们不能在编译时被检查,并且它们不属于单元测试的范围。
206206

207-
#### Java断言语法
207+
#### Java 断言语法
208208

209-
你可以通过其它程序设计架构来模拟断言的效果,因此,在Java中包含断言的意义在于它们易于编写。断言语句有两种形式 :
209+
你可以通过其它程序设计架构来模拟断言的效果,因此,在 Java 中包含断言的意义在于它们易于编写。断言语句有两种形式 :
210210

211211
assert boolean-expression;
212212

213213
assert boolean-expression: information-expression;
214214

215-
两者似乎告诉我们 **我断言这个布尔表达式会产生一个真正的值**, 否则,将抛出**AssertionError**异常。
215+
两者似乎告诉我们 **我断言这个布尔表达式会产生 true**, 否则,将抛出 **AssertionError** 异常。
216216

217-
这是**Throwable**的派生类,因此不需要异常规范
217+
**AssertionError****Throwable** 的派生类,因此不需要异常说明
218218

219219
不幸的是,第一种断言形式的异常不会生成包含布尔表达式的任何信息(与大多数其他语言的断言机制相反)。
220220

@@ -229,7 +229,7 @@ assert boolean-expression: information-expression;
229229
// {ThrowsException}
230230
public class Assert1 {
231231
public static void main(String[] args) {
232-
assert false;
232+
assert false;
233233
}
234234
}
235235

@@ -240,9 +240,9 @@ at Assert1.main(Assert1.java:9)
240240
*/
241241
```
242242

243-
如果你正常运行程序,没有任何特殊的断言标志,则不会发生任何事情。你需要在运行程序时显式启用断言。一种简单的方法是使用 **-ea** flag, 它也可以表示为: **-enableassertion** , 这将运行程序并执行任何断言语句。
243+
如果你正常运行程序,没有任何特殊的断言标志,则不会发生任何事情。你需要在运行程序时显式启用断言。一种简单的方法是使用 **-ea** 标志, 它也可以表示为: **-enableassertion**, 这将运行程序并执行任何断言语句。
244244

245-
输出中并没有包含多少有用的信息。另一方面,如果你使用 **information-expression** , 将生成一条有用的消息作为异常堆栈跟踪的一部分。最有用的 **information-expression** 通常是一串针对程序员的文本:
245+
输出中并没有包含多少有用的信息。另一方面,如果你使用 **information-expression** , 将生成一条有用的消息作为异常堆栈跟踪的一部分。最有用的 **information-expression** 通常是一串针对程序员的文本
246246

247247
```java
248248
// validating/Assert2.java
@@ -264,11 +264,11 @@ at Assert2.main(Assert2.java:8)
264264
*/
265265
```
266266

267-
**information-expression** 可以产生任何类型的对象,因此,通常将构造一个包含对象值的更复杂的字符串,它是否与失败的断言有关
267+
**information-expression** 可以产生任何类型的对象,因此,通常将构造一个包含对象值的更复杂的字符串,它包含失败的断言
268268

269-
还可以通过类名或包名打开或关闭断言;也就是说,你可以为整个包启用或禁用断言。实现这一点的详细信息在JDK的断言文档中。你想要打开或关闭某些断言时,此特性对于使用断言进行工具化的大型项目非常有用。但是,日志记录(*Logging*)或者调试(*Debugging*),可能是捕获这类信息的更好工具。
269+
你还可以基于类名或包名打开或关闭断言;也就是说,你可以对整个包启用或禁用断言。实现这一点的详细信息在 JDK 的断言文档中。此特性对于使用断言的大型项目来说很有用当你想打开或关闭某些断言时。但是,日志记录(*Logging*)或者调试(*Debugging*),可能是捕获这类信息的更好工具。
270270

271-
这有另一种办法控制你的断言:编程方式,通过链接到类加载器对象**ClassLoader**)。类加载器中有几种方法允许动态启用和禁用断言,其中 **setDefaultAssertionStatus ()** ,它为之后加载的所有类设置断言状态。因此,你可以认为你像下面这样悄悄地开启了断言
271+
你还可以通过编程的方式通过链接到类加载器对象**ClassLoader**来控制断言。类加载器中有几种方法允许动态启用和禁用断言,其中 **setDefaultAssertionStatus ()** ,它为之后加载的所有类设置断言状态。因此,你可以像下面这样悄悄地开启断言
272272

273273
```java
274274
// validating/LoaderAssertions.java
@@ -298,27 +298,23 @@ LoaderAssertions.main(LoaderAssertions.java:9)
298298
*/
299299
```
300300

301-
这消除了在运行程序时在命令行上使用 **-ea** 标志的需要,使用 **-ea** 标志启用断言可能同样简单。当交付独立产品时,可能必须设置一个执行脚本让用户能够启动程序,配置其他启动参数。这是有道理的,然而,决定在程序运行时启用断言可以使用下面的 **static** 块来实现这一点,该语句位于系统的主类中:
301+
这消除了在运行程序时在命令行上使用 **-ea** 标志的需要,使用 **-ea** 标志启用断言可能同样简单。当交付独立产品时,可能必须设置一个执行脚本让用户能够启动程序,配置其他启动参数,这么做是有意义的。然而,决定在程序运行时启用断言可以使用下面的 **static** 块来实现这一点,该语句位于系统的主类中:
302302

303303
```java
304304
static {
305305
boolean assertionsEnabled = false;
306306
// Note intentional side effect of assignment:
307307
assert assertionsEnabled = true;
308308
if(!assertionsEnabled)
309-
throw new RuntimeException("Assertions disabled");
309+
throw new RuntimeException("Assertions disabled");
310310
}
311311
```
312312

313-
314-
315313
如果启用断言,然后执行 **assert** 语句,**assertionsEnabled** 变为 **true** 。断言不会失败,因为分配的返回值是赋值的值。如果不启用断言,**assert** 语句不执行,**assertionsEnabled** 保持false,将导致异常。
316314

317-
318-
319315
#### Guava断言
320316

321-
因为启用Java本地断言很麻烦,Guava团队添加一个始终启用替换断言的 **Verify** 类。他们建议静态导入 **Verify** 方法:
317+
因为启用 Java 本地断言很麻烦,Guava 团队添加一个始终启用的用来替换断言的 **Verify** 类。他们建议静态导入 **Verify** 方法:
322318

323319
```java
324320
// validating/GuavaAssertions.java
@@ -373,12 +369,8 @@ Shouldn't be null: arg s
373369
*/
374370
```
375371

376-
377-
378372
这里有两个方法,使用变量 **verify()****verifyNotNull()** 来支持有用的错误消息。注意,**verifyNotNull()** 内置的错误消息通常就足够了,而 **verify()** 太一般,没有有用的默认错误消息。
379373

380-
381-
382374
#### 使用断言进行契约式设计
383375

384376
*契约式设计(DbC)*是Bertrand Meyer提出的一个概念,Eiffel语言的发明者,通过确保对象遵循某些规则来帮助创建健壮的程序。这些规则是由正在解决的问题的性质决定的,这超出了编译器可以验证的范围。虽然断言没有直接实现 **DBC**(Eiffel也是如此),但是它们创建了一种非正式的DBC编程风格。DbC假定服务供应商与该服务的消费者或客户之间存在明确指定的契约。在面向对象编程中,服务通常由对象提供,对象的边界 — 供应商和消费者之间的划分 — 是对象类的接口。当客户端调用特定的公共方法时,它们希望该调用具有特定的行为:对象状态改变,以及一个可预测的返回值。

0 commit comments

Comments
 (0)