So far, you have seen how to declare closures and how to call them. However, there is one crucial topic that we haven’t touched yet: how to return from a closure. In principle, there are two ways of returning:
This means the following ways of doubling the entries of a list have the very same effect:
WARNING: There is a difference between using the return keyword inside and outside of a closure.
Support for design patterns:
Design patterns are widely used by developers to enhance the quality of their designs. Each design pattern presents a typical problem that occurs in object-oriented programming along with a corresponding well-tested solution. Let’s take a closer look at the way the availability of closures affects how, which, and when patterns are used. If you’ve never seen design patterns before, we suggest you look at the classic book Design Patterns: Elements of Reusable Object-Oriented Software by Gamma et al, or one of the more recent ones such as Head First Design Patterns by Freeman et al or Refactoring to Patterns by Joshua Kerievsky, or search for “patterns repository” or “patterns catalog” using your favorite search engine.
Although many design patterns are broadly applicable and apply to any language, some of them are particularly well-suited to solving issues that occur when using programming languages such as C++ and Java. They most often involve implementing new abstractions and new classes to make the original programs more flexible or maintainable. With Groovy, some of the restrictions that face C++ and Java do not apply, and the design patterns are either of less value or more directly supported using language features rather than introducing new classes. We pick two examples to show the difference: the Visitor and Builder patterns. As you’ll see, closures and dynamic typing are the key differentiators in Groovy that facilitate easier pattern usage.
Relationship to the Visitor pattern
The Visitor pattern is particularly useful when you wish to perform some complex business functionality on a composite collection (such as a tree or list) of existing simple classes. Rather than altering the existing simple classes to contain the desired business functionality, a Visitor object is introduced. The Visitor knows how to traverse the composite collection and knows how to perform the business functionality for different kinds of a simple class. If the composite changes or the business functionality changes over time, typically only the Visitor class is impacted.
Listing 5.10 shows how simple the Visitor pattern can look in Groovy; the composite traversal code is in the accept method of the Drawing class, whereas the business functionality (in our case to perform some calculations involving shape area) is contained in two closures, which are passed as parameters to the appropriate acceptmethods. There is no need for a separate Visitor class in this simple case.
Listing 5.10 The Visitor pattern in Groovy
Relationship to the Builder pattern
The Builder pattern serves to encapsulate the logic associated with constructing a product from its constituent parts. When using the pattern, you normally create aBuilder class, which contains logic determining what builder methods to call and in which sequence to call them to ensure proper assembly of the product. For each product, you must supply the appropriate logic for each relevant builder method used by the Builder class; each builder method typically returns one of the constituent parts. Coding Java solutions based on the Builder pattern is not hard, but the Java code tends to be cumbersome and verbose and doesn’t highlight the structure of the assembled product. For that reason, the Builder pattern is rarely used in Java; developers instead use unstructured or replicated builder-type logic mixed in with their other code. This is a shame, because the Builder pattern is so powerful. 底下是 Builder Pattern 的典型應用 Maze Builder 使用 Groovy 改寫的 Code:
trarily nested node structures, produce markup like HTML or XML, define GUIs in Swing or other widget toolkits, and even access the wide range of functionality in Ant. You will see lots of examples in chapter 8, and we explain how to write your own builders in section 8.6.
Relationship to other patterns
Almost all patterns are easier to implement in Groovy than in Java. This is often because Groovy supports more lightweight solutions that make the patterns less of a necessity—mostly because of closures and dynamic typing. In addition, when patterns are required, Groovy often makes expressing them more succinct and simpler to set up.
We discuss a number of patterns in other sections of this book, patterns such as Strategy (see 9.1.1 and 9.1.3), Observer (see 13.2.3), and Command (see 9.1.1) benefit from using closures instead of implementing new classes. Patterns such as Adapter and Decorator (see 7.5.3) benefit from dynamic typing and method lookup. We also briefly discuss patterns such as Template Method (see section 5.2.2), the Value Object pattern (see 3.3.2), the incomplete library class smell (see 7.5.3), MVC (see 8.5.6), and the DTO and DAO patterns (see chapter 10). Just by existing, closures can completely replace the Method Object pattern.