私は、メタクラス プログラミングを行ったり、Grails アプリケーションを開発するときに Groovy の動的機能を (明示的に) 利用したりしていません。私は見逃しているように感じます。Grails プロジェクトで Groovy の動的機能をどこで、いつ、どのように使用するかの例をいくつか挙げていただけますか (たとえば、ドメイン、コントローラーにメソッドを追加しますか)。
2 に答える
Grails プロジェクトではありませんが、広範な Groovy コードを含む JBoss Seam プロジェクトで 2 年間働きました。通常、最初の引数メソッドが通常モデル クラスであるいくつかのサービス クラスがありました。カテゴリを通じて、それらは実際にオブジェクト指向になりました。
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にも当てはまると思います。
また、多くの位置テキスト ファイルを作成し、特にカテゴリの下で多くのグルーヴィーなメソッドを使用しました。
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 メソッドにフックしました (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")
}
}
打ち負かすのは難しい:-)
私はメタ プログラミング機能を使用して、アプリケーション レベルでの作業を容易にしています。
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')