Skip to content
Skip to breadcrumbs
Skip to header menu
Skip to action menu
Skip to quick search
Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Dashboard
Groovy
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Page Layout
No Layout
Two column (simple)
Two column (simple, left sidebar)
Two column (simple, right sidebar)
Three column (simple)
Two column
Two column (left sidebar)
Two column (right sidebar)
Three column
Three column (left and right sidebars)
Undo
Redo
Find/Replace
Keyboard Shortcuts Help
<p>The <a href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator Pattern</a> provides a mechanism to embellish the behaviour of an object without changing its essential interface. A decorated object should be able to be substituted wherever the original (non-decorated) object was expected. Decoration typically does not involve modifying the source code of the original object and decorators should be able to be combined in flexible ways to produce objects with several embellishments.</p> <h3>Traditional Example</h3> <p>Suppose we have the following <code>Logger</code> class.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class Logger { def log(String message) { println message } } </pre></td></tr></table> <p>There might be times when it is useful to timestamp a log message, or times when we might want to change the case of the message. We could try to build all of this functionality into our <code>Logger</code> class. If we did that, the <code>Logger</code> class would start to be very complex. Also, everyone would obtain all of features even when they might not want a small subset of the features. Finally, feature interaction would become quite difficult to control.</p> <p>To overcome these drawbacks, we instead define two decorator classes. Uses of the <code>Logger</code> class are free to embellish their base logger with zero or more decorator classes in whatever order they desire. The classes look like this:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class TimeStampingLogger extends Logger { private Logger logger TimeStampingLogger(logger) { this.logger = logger } def log(String message) { def now = Calendar.instance logger.log("$now.time: $message") } } class UpperLogger extends Logger { private Logger logger UpperLogger(logger) { this.logger = logger } def log(String message) { logger.log(message.toUpperCase()) } } </pre></td></tr></table> <p>We can use the decorators like so:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def logger = new UpperLogger(new TimeStampingLogger(new Logger())) logger.log("G'day Mate") // => Tue May 22 07:13:50 EST 2007: G'DAY MATE </pre></td></tr></table> <p>You can see that we embellish the logger behaviour with both decorators. Because of the order we chose to apply the decorators, our log message comes out capitalised and the timestamp is in normal case. If we swap the order around, let's see what happens:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> logger = new TimeStampingLogger(new UpperLogger(new Logger())) logger.log('Hi There') // => TUE MAY 22 07:13:50 EST 2007: HI THERE </pre></td></tr></table> <p>Now the timestamp itself has also been changed to be uppercase.</p> <h3>A touch of dynamic behaviour</h3> <p>Our previous decorators were specific to <code>Logger</code> objects. We can use Groovy's Meta-Object Programming capabilities to create a decorator which is far more general purpose in nature. Consider this class:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class GenericLowerDecorator { private delegate GenericLowerDecorator(delegate) { this.delegate = delegate } def invokeMethod(String name, args) { def newargs = args.collect{ arg -> if (arg instanceof String) return arg.toLowerCase() else return arg } delegate.invokeMethod(name, newargs) } } </pre></td></tr></table> <p>It takes any class and decorates it so that any <code>String</code> method parameter will automatically be changed to lower case.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> logger = new GenericLowerDecorator(new TimeStampingLogger(new Logger())) logger.log('IMPORTANT Message') // => Tue May 22 07:27:18 EST 2007: important message </pre></td></tr></table> <p>Just be careful with ordering here. The original decorators were restricted to decorating <code>Logger</code> objects. This decorator work with any object type, so we can't swap the ordering around, i.e. this won't work:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> // Can't mix and match Interface-Oriented and Generic decorators // logger = new TimeStampingLogger(new GenericLowerDecorator(new Logger())) </pre></td></tr></table> <p>We could overcome this limitation be generating an appropriate Proxy type at runtime but we won't complicate the example here.</p> <h3>Runtime behaviour embellishment</h3> <p>You can also consider using the <code>ExpandoMetaClass</code> from Groovy 1.1 to dynamically embellish a class with behaviour. This isn't the normal style of usage of the decorator pattern (it certainly isn't nearly as flexible) but may help you to achieve similar results in some cases without creating a new class.</p> <p>Here's what the code looks like:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> // current mechanism to enable ExpandoMetaClass GroovySystem.metaClassRegistry.metaClassCreationHandle = new ExpandoMetaClassCreationHandle() def logger = new Logger() logger.metaClass.log = { String m -> println 'message: ' + m.toUpperCase() } logger.log('x') // => message: X </pre></td></tr></table> <p>This achieves a similar result to applying a single decorator but we have no way to easily apply and remove embellishments on the fly.</p> <h3>More dynamic decorating</h3> <p>Suppose we have a calculator class. (Actually any class would do.)</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class Calc { def add(a, b) { a + b } } </pre></td></tr></table> <p>We might be interested in observing usage of the class over time. If it is buried deep within our codebase, it might be hard to determine when it is being called and with what parameters. Also, it might be hard to know if it is performing well. We can easily make a generic tracing decorator that prints out tracing information whenever any method on the <code>Calc</code> class is called and also provide timing information about how long it took to execute. Here is the code for the tracing decorator:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class TracingDecorator { private delegate TracingDecorator(delegate) { this.delegate = delegate } def invokeMethod(String name, args) { println "Calling $name$args" def before = System.currentTimeMillis() def result = delegate.invokeMethod(name, args) println "Got $result in ${System.currentTimeMillis()-before} ms" result } } </pre></td></tr></table> <p>Here is how to use the class in a script:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def tracedCalc = new TracingDecorator(new Calc()) assert 15 == tracedCalc.add(3, 12) </pre></td></tr></table> <p>And here is what you would see after running this script:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> Calling add{3, 12} Got 15 in 31 ms </pre></td></tr></table> <h3>Decorating with an Interceptor</h3> <p>The above timing example hooks into the lifecycle of Groovy objects (via <code>invokeMethod</code>). This is such an important style performing meta-programming that Groovy has special support for this style of decorating using <em>interceptors</em>.</p> <p>Groovy even comes with a built-in <code>TracingInterceptor</code>. We can extend the built-in class like this:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class TimingInterceptor extends TracingInterceptor { private beforeTime def beforeInvoke(object, String methodName, Object[] arguments) { super.beforeInvoke(object, methodName, arguments) beforeTime = System.currentTimeMillis() } public Object afterInvoke(Object object, String methodName, Object[] arguments, Object result) { super.afterInvoke(object, methodName, arguments, result) def duration = System.currentTimeMillis() - beforeTime writer.write("Duration: $duration ms\n") writer.flush() return result } } </pre></td></tr></table> <p>Here is an example of using this new class:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def proxy = ProxyMetaClass.getInstance(util.CalcImpl.class) proxy.interceptor = new TimingInterceptor() proxy.use { assert 7 == new util.CalcImpl().add(1, 6) } </pre></td></tr></table> <p>And here is the output:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> before util.CalcImpl.ctor() after util.CalcImpl.ctor() Duration: 0 ms before util.CalcImpl.add(java.lang.Integer, java.lang.Integer) after util.CalcImpl.add(java.lang.Integer, java.lang.Integer) Duration: 16 ms </pre></td></tr></table> <h3>Decorating with java.lang.reflect.Proxy</h3> <p>If you are trying to decorate an object (i.e. just a particular instance of the class, not the class generally), then you can use Java's <code>java.lang.reflect.Proxy</code>. Groovy makes working with this easier than just Java. Below is a code sample taken out of a grails project that wraps a <code>java.sql.Connection</code> so that it's close method is a no-op:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> protected Sql getGroovySql() { final Connection con = session.connection() def invoker = { object, method, args -> if (method.name == "close") { log.debug("ignoring call to Connection.close() for use by groovy.sql.Sql") } else { log.trace("delegating $method") return con.invokeMethod(method.name,args) } } as InvocationHandler; def proxy = Proxy.newProxyInstance( getClass().getClassLoader(), [Connection] as Class[], invoker ) return new Sql(proxy) } </pre></td></tr></table> <p>If there were many methods to intercept, then this approach could be modified to look up closure in a map by method name and invoke it.</p> <h3>Decorating with Spring</h3> <p>The <a href="http://www.springframework.org/">Spring Framework</a> allows decorators to be applied with <em>interceptors</em> (you may have heard the terms <em>advice</em> or <em>aspect</em>). You can leverage this mechanism from Groovy as well.</p> <p>First define a class that you want to decorate (we'll also use an interface as is normal Spring practice):</p> <p>Here's the interface:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> package util interface Calc { def add(a, b) } </pre></td></tr></table> <p>Here's the class:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> package util class CalcImpl implements Calc { def add(a, b) { a + b } } </pre></td></tr></table> <p>Now, we define our wiring in a file called <code>beans.xml</code> as follows:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd"> <bean id="performanceInterceptor" autowire="no" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"> <property name="loggerName" value="performance"/> </bean> <bean id="calc" class="util.CalcImpl"/> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames" value="calc"/> <property name="interceptorNames" value="performanceInterceptor"/> </bean> </beans> </pre></td></tr></table> <p>Now, our script looks like this:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> import org.springframework.context.support.ClassPathXmlApplicationContext def ctx = new ClassPathXmlApplicationContext("beans.xml") def calc = ctx.getBean('calc') println calc.add(3, 25) </pre></td></tr></table> <p>And when we run it, we see the results:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> 21/05/2007 23:02:35 org.springframework.aop.interceptor.PerformanceMonitorInterceptor invokeUnderTrace FINEST: StopWatch 'util.Calc.add': running time (millis) = 16 </pre></td></tr></table> <p>You may have to adjust your <code>logging.properties</code> file for messages at log level <code>FINEST</code> to be displayed.</p> <h3>Asynchronous Decorators using GPars</h3> <p>Using the example code in <a href="http://www.cs.iastate.edu/~design/projects/panini/docs/starting.shtml">Panini</a> for inspiration. Here is a Groovy version that avoids using an <code>@AddedBehavior</code> annotation at the expense of not having as general an algorithm for selecting the methods to decorate. This isn't a limitation of the particular approach chosen but just a simplification for illustrative purposes (but don't assume below is an exact equivalent).</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> @Grab('org.codehaus.gpars:gpars:0.10') import static groovyx.gpars.GParsPool.withPool interface Document { void print() String getText() } class DocumentImpl implements Document { def document void print() { println document } String getText() { document } } def words(String text) { text.replaceAll(/[^a-zA-Z]/, ' ').trim().split(/\s+/)*.toLowerCase() } def avgWordLength = { def words = words(it.text) sprintf "Avg Word Length: %4.2f", words*.size().sum() / words.size() } def modeWord = { def wordGroups = words(it.text).groupBy {it}.collectEntries{ k, v -> [k, v.size()] } def maxSize = wordGroups*.value.max() def maxWords = wordGroups.findAll{ it.value == maxSize } "Mode Word(s): ${maxWords*.key.join(', ')} ($maxSize occurrences)" } def wordCount = { d -> "Word Count: " + words(d.text).size() } def asyncDecorator(Document d, Closure c) { ProxyGenerator.INSTANCE.instantiateDelegate([print: { withPool { def result = c.callAsync(d) d.print() println result.get() } }], [Document], d) } Document d = asyncDecorator(asyncDecorator(asyncDecorator( new DocumentImpl(document:"This is the file with the words in it\n\t\nDo you see the words?\n"), // new DocumentImpl(document: new File('AsyncDecorator.groovy').text), wordCount), modeWord), avgWordLength) d.print() </pre></td></tr></table>
Please type the word appearing in the picture.
Attachments
Labels
Location
Watch this page
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced