Programming with closures
Recently I caught myself thinking that my programming habits are changing while programming in Groovy. In particular, I started using closures more and more to clean up my code, make it more DRYer, e.g. by not just merely using existing closures provided by libraries such as GDK, GORM, etc., but by creating my own closures.
Here's a small example from GrailsCrowd. The idea here is to either 'accept project participation invitation' or 'reject project participation invitation'. So, in the Controller, I factored out the common code of retrieving the Member, Project, redirecting to the appropriate action afterwards, etc. to a private method which takes a closure, and calling that closure for the actual action of 'acceptance' or 'rejection':
private def withProject(callable) {
def invitee = freshCurrentlyLoggedInMember()
def creator = Member.findByName(params.creator)
def project = GrailsProject.get(params.projectId)
//Call the closure
callable([project:project,creator:creator,invitee:invitee])
redirect(controller: 'mailbox')
}
def acceptParticipationInvitation = {
withProject {projectMap ->
projectMap.project.acknowlegeParticipationAcceptance(projectMap.creator,
projectMap.invitee, params.messageId.toLong())
}
}
def rejectParticipationInvitation = {
withProject {projectMap ->
projectMap.project.rejectParticipationInvitation(projectMap.creator,
projectMap.invitee, params.messageId.toLong())
}
}
IMO, this makes code cleaner, reusable, and more maintainable. Also, this style of programming with closures kind of replaces good old Template Method design pattern.
Keep on Groovying, folks!
Later...

5 comments:
Or is just way of using the template pattern just using the idiom of the language you're working in?
You could put it that way too. The wording is not important. The most important thing (for me) is that it makes my code cleaner.
Groovy seems to be converting people to (at least some of) the ways of functional programming without the usual kicking and screaming. Hooray for that.
You're using the standard FP technique of higher-order functions with an anonymous function (not really a closure) as a parameter. Though it seems to me that you could (and maybe should) use regular parameters rather than a map:
withProject {project, creator, invitee ->
// etc.
}
// elsewhere:
callable(project, creator, invitee)
@john You are right, could use the parameters to the function (closure). I chose Map for convenience, perhaps.
Yes, those are anonymous lambdas, blocks, whatever one might call them, and might not be true closures as academically defined, but Groovy calls them closures anyway ;-)
http://groovy.codehaus.org/Closures+-+Formal+Definition
Yes, closures can save configurations and provide a flexible alternative for subclassing/template methods.
Another example: Data import from files/streams (the closure is used for data processing - save or print or transform). Example:
http://code.google.com/p/agimatec-tools/wiki/DBImportExample
Post a Comment