| ////////////////////////////////////////// |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| |
| ////////////////////////////////////////// |
| |
| = Delegation Pattern |
| |
| The http://en.wikipedia.org/wiki/Delegation_pattern[Delegation Pattern] is a technique where an object's behavior (public methods) is implemented by delegating responsibility to one or more associated objects. |
| |
| Groovy allows the traditional style of applying the delegation pattern, e.g. see <<_replace_inheritance_with_delegation,Replace Inheritance with Delegation>>. |
| |
| == Implement Delegation Pattern using ExpandoMetaClass |
| |
| The gapi:groovy.lang.ExpandoMetaClass[] allows usage of this pattern to be encapsulated in a library. This allows Groovy to emulate similar libraries available for the Ruby language. |
| |
| Consider the following library class: |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=delegation_delegator,indent=0] |
| ---- |
| |
| With this in your classpath, you can now apply the delegation pattern dynamically as shown in the following examples. First, consider we have the following classes: |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=delegation_classes,indent=0] |
| ---- |
| |
| We can now use the __delegator__ to automatically borrow methods from the __lender__ object to extend the __Person__ class. We can borrow the methods as is or with a rename: |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=delegation_usage,indent=0] |
| ---- |
| |
| The first line above, adds the __borrowFor__ method to the __Person__ class by delegating to the __lender__ object. The second line adds a __getMoney__ method to the __Person__ class by delegating to the __lender__ object's __borrowAmount__ method. |
| |
| Alternatively, we could borrow multiple methods like this: |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=delegation_usage2,indent=0] |
| ---- |
| |
| Which adds these two methods to the __Person__ class. |
| |
| Or if we want all the methods, like this: |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=delegation_usage3,indent=0] |
| ---- |
| |
| Which will make all the methods in the delegate object available in the __Person__ class. |
| |
| Alternatively, we can use a map notation to rename multiple methods: |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=delegation_usage4,indent=0] |
| ---- |
| |
| == Implement Delegation Pattern using @Delegate annotation |
| |
| Since version 1.6 you can use the built-in delegation mechanism which is based on AST transformation. |
| |
| This make delegation even easier: |
| |
| [source,groovy] |
| ---- |
| include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=delegation_annotation,indent=0] |
| ---- |