You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2020/08/29 05:48:30 UTC
[groovy] branch master updated: doco: closure/lambda versions of
the decorator pattern
This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 43741fa doco: closure/lambda versions of the decorator pattern
43741fa is described below
commit 43741fa286306855ce73239fedb89d5de816c780
Author: Paul King <pa...@asert.com.au>
AuthorDate: Sat Aug 29 15:48:21 2020 +1000
doco: closure/lambda versions of the decorator pattern
---
.../doc/fragment_design-pattern-decorator.adoc | 23 +++++++++++++--
src/spec/test/DesignPatternsTest.groovy | 34 ++++++++++++++++++++++
2 files changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/spec/doc/fragment_design-pattern-decorator.adoc b/src/spec/doc/fragment_design-pattern-decorator.adoc
index 722f955..0ea7de5 100644
--- a/src/spec/doc/fragment_design-pattern-decorator.adoc
+++ b/src/spec/doc/fragment_design-pattern-decorator.adoc
@@ -57,6 +57,24 @@ include::../test/DesignPatternsTest.groovy[tags=decorator_traditional_usage2,ind
Now the timestamp itself has also been changed to be uppercase.
+== Simplifying with closures or lambdas
+
+Closures make it easy to represent code. We can use that fact to
+make a general purpose logger class that accepts the decoration code as a closure.
+This saves us defining many decoration classes.
+
+[source,groovy]
+----
+include::../test/DesignPatternsTest.groovy[tags=decorating_logger_closure,indent=0]
+----
+
+We can use the same approach with lambdas:
+
+[source,groovy]
+----
+include::../test/DesignPatternsTest.groovy[tags=decorating_logger_lambda,indent=0]
+----
+
== A touch of dynamic behaviour
Our previous decorators were specific to `Logger` 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:
@@ -167,7 +185,7 @@ If there were many methods to intercept, then this approach could be modified to
== Decorating with Spring
-The http://www.springframework.org[Spring Framework] allows decorators to be applied with __interceptors__ (you may have heard the terms __advice__ or __aspect__). You can leverage this mechanism from Groovy as well.
+The https://spring.io/[Spring Framework] allows decorators to be applied with __interceptors__ (you may have heard the terms __advice__ or __aspect__). You can leverage this mechanism from Groovy as well.
First define a class that you want to decorate (we'll also use an interface as is normal Spring practice):
@@ -227,7 +245,8 @@ You may have to adjust your `logging.properties` file for messages at log level
== Asynchronous Decorators using GPars
-The following example is inspired by some of the early example code for the http://design.cs.iastate.edu/~panini/[Panini] programming language.
+The following example is inspired by some of the early example code for the
+http://design.cs.iastate.edu/~panini/[Panini] programming language.
These days, you'll see this style used with async functions in JavaScript.
[source,groovy]
diff --git a/src/spec/test/DesignPatternsTest.groovy b/src/spec/test/DesignPatternsTest.groovy
index fe4d62e..29bbfe7 100644
--- a/src/spec/test/DesignPatternsTest.groovy
+++ b/src/spec/test/DesignPatternsTest.groovy
@@ -808,6 +808,40 @@ class DesignPatternsTest extends CompilableTestSupport {
logger.log('x')
// => message: X
// end::decorator_runtime_behaviour[]
+ // tag::decorating_logger_closure[]
+ class DecoratingLogger {
+ def decoration = Closure.IDENTITY
+
+ def log(String message) {
+ println decoration(message)
+ }
+ }
+
+ def upper = { it.toUpperCase() }
+ def stamp = { "$Calendar.instance.time: $it" }
+ def logger = new DecoratingLogger(decoration: stamp << upper)
+ logger.log("G'day Mate")
+ // Sat Aug 29 15:28:29 AEST 2020: G'DAY MATE
+ // end::decorating_logger_closure[]
+ '''
+ shouldCompile '''
+ // tag::decorating_logger_lambda[]
+ import java.util.function.Function
+
+ class DecoratingLogger {
+ Function<String, String> decoration = Function.identity()
+
+ def log(String message) {
+ println decoration.apply(message)
+ }
+ }
+
+ Function<String, String> upper = s -> s.toUpperCase()
+ Function<String, String> stamp = s -> "$Calendar.instance.time: $s"
+ def logger = new DecoratingLogger(decoration: upper.andThen(stamp))
+ logger.log("G'day Mate")
+ // => Sat Aug 29 15:38:28 AEST 2020: G'DAY MATE
+ // end::decorating_logger_lambda[]
'''
}