演化架构和紧急设计: 使用 Groovy 构建 DSL
2010-10-09 08:12:32 来源:WEB开发网queue.dequeue().shouldBe(val)
但是 Queue 类的检查显示它没有一个 shouldBe()方法。那么它是从哪里来的呢?
如果您查看 it() 方法的定义,您将可以看到 categories 用在何处来扩展已有类。清单 9 显示 it() 方法的声明:
清单 9. it() 方法的声明
def it(spec, closure) {
stepStack.startStep(listener, BehaviorStepType.IT, spec)
closure.delegate = new EnsuringDelegate()
try {
if (beforeIt != null) {
beforeIt()
}
listener.gotResult(new Result(Result.SUCCEEDED))
use(BehaviorCategory) {
closure()
}
if (afterIt != null) {
afterIt()
}
} catch (Throwable ex) {
listener.gotResult(new Result(ex))
}
stepStack.stopStep(listener)
}
大约一半的方法,作为参数传递的封闭块将在 BehaviorCategory 类中执行,清单 10 显示了其中的一部分:
清单 10. BehaviorCategory 类的一部分
static void shouldBe(Object self, value, String msg) {
isEqual(self, value, msg)
}
private static void isEqual(self, value, String msg) {
if (self.getClass() == NullObject.class) {
if (value != null) {
throwValidationException(
"expected ${value.toString()} but target object is null", msg)
}
} else if (value.getClass() == String.class) {
if (!value.toString().equals(self.toString())) {
throwValidationException(
"expected ${value.toString()} but was ${self.toString()}", msg)
}
} else {
if (value != self) {
throwValidationException("expected ${value} but was ${self}", msg)
}
}
}
BehaviorCategory 是一个 category ,其方法扩增了 Object,阐述了开放类令人难以置信的力量。向 Object 添加一个新方法,这使得向每个类(包括 Queue)添加一个 shouldBe() 方法变得十分容易。您不能使用核心 Java 代码进行这一操作,这样做太麻烦了,甚至没法入手。categories 的使用加强了我之前的建议:它将对 Object 的修改范围限制为 easyb DSL 中 use 子句。
结束语
我想让我捕获的惯用模式从其余的代码中脱颖而出,DSL 提供一个令人信服的机制来实现这一目标。使用支持它们的语言编写 DSL 非常容易,不像使用 Java 语言那样。如果您组织的外部力量妨碍您利用非 Java 语言的优势,不要放弃。像 Spring 框架这类语言越来越多地支持其他语言,比如 Groovy 或 Clojure。您可以使用这些语言来创建部件并让 Spring 将其注入到您应用程序的合适位置。许多组织在使用其他语言方面太过保守,但是通过 Spring 这类框架很容易增加线路。
下一期中,我将使用几个 JRuby 实例集中精力介绍使用 DSL 作为一种方法捕获领域惯用模式,阐述可以将语言的表现力呈现得多深入 。
更多精彩
赞助商链接