在开发 Grails 应用程序时,我没有进行任何元类编程或(明确地)利用 Groovy 的任何动态特性。我觉得我错过了。您能否举例说明您在 Grails 项目中何时/何时/如何使用 Groovy 的动态特性(您是否向域中添加方法,例如控制器)?
问问题
217 次
2 回答
1
不是 Grails 项目,但我在 JBoss Seam 项目中工作了两年,其中包含大量 Groovy 代码。我们通常有一些服务类,其第一个参数方法通常是模型类。通过类别,它们变得真正面向对象:
class InvoiceService {
static void sendToWs(Invoice invoice, wsEndpoint) {
// neat stuff
}
static void validate(Invoice invoice) throws InvoiceValidationException {
// more neat stuff
}
static InternationalInvoice buildInternationalInvoice(Invoice invoice) {
// builds new object
}
}
def invoice = new Invoice()
use(InvoiceService) {
invoice.validate()
invoice.sendToWs endpoint
}
我相信这同样适用于 Grails。
我们还构建了很多位置文本文件,并且我们在类别下使用了很多 groovy 方法:
class PositionalFormatCategory {
static String pad(String value, Integer times) {
value.trim().padRight times, " "
}
static String pad(BigDecimal value, Integer times) {
value.toString().padLeft times, " "
}
}
但是Groovy 在解析/编写XML 方面确实令人震惊。我们有一个模型类,必须转换为 4 种不同的 XML 格式
class XmlFormat1 {
ServiceInvoice invoice
String toXml() {
new StreamingMarkupBuilder().bind {
xml {
price invoice.value
date invoice.creationDate
invoice.items.each { item ->
invoiceItem {
price item.price
quantity item.qty
}
}
}
}
}
}
我们使用元编程来挂钩一个小的 lib 方法,该方法连接到一个可能已关闭的 rest 服务(我不记得 lib 名称)。我们使用它来定义超时,否则它会花一整天时间而不会失败:
def oldConnect = RestConn.metaClass.&connect
RestConn.metaClass.connect = {
try {
delegate.setTimeout 5000
oldConnect()
} catch (TimeoutException t) {
throw new BusinessException("Timeout connecting to the server")
}
}
难以击败:-)
于 2013-02-04T12:04:13.487 回答
0
我使用元编程功能使处理应用程序级别的事情变得更容易。
EG 我们有一个搜索引擎,它需要在创建/更新时对事物进行索引,并且还需要一些动态查找器方法来从索引中获取内容。
class SearchableClass {
static searchable = ['foo']
String foo
}
def searchService = [ search:{ Class clazz, Map opts, String query -> // This would be a real service
// doSearch
query.collect { it }
} ]
def searchBindService = [ bindSearch:{ Class clazz -> // This would be a real service
clazz.metaClass.static.with {
search = searchService.search.curry(clazz, [:])
searchOne = { String q ->
searchService.search(clazz, [:], q).take(1)
}
}
} ]
[SearchableClass, String, Map, List].findAll { // Only get things that have the 'searchable' static prop
try {
it.searchable != null
}catch(e){ }
}.each searchBindService.bindSearch
assert ["q", "u", "e", "r", "y"] == SearchableClass.search('query')
assert ["q"] == SearchableClass.searchOne('query')
于 2013-02-04T10:48:36.297 回答