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[]
         '''
     }