Recipe17.5.Implementing the Builder Pattern


Recipe 17.5. Implementing the Builder Pattern

Problem

You want to apply the builder pattern using AspectJ.

Solution

The builder pattern captures the complex steps that may be needed in the creation of a particular object. The steps are implemented as methods on the builder class; after each of the required steps has been completed, then the builder can be called to create the resulting built object.

To implement the builder pattern using AspectJ, create an aspect that adds to the top-level builder class a field to store the build result and a method to access that result using static cross-cutting techniques. This enables the builder to be an interface and not an abstract class.

Discussion

The builder pattern can be implemented using aspects, as shown in Example 17-7.

Example 17-7. Applying the builder pattern using aspects
public interface TextPhraseBuilder {    public void buildHeader(String title);             public void buildBody(String content);             public void buildFooter(String closingContent);             public String getResult( ); } public aspect TextPhraseBuilderDefaultImplementation  {    public StringBuffer TextPhraseBuilder.result = new StringBuffer( );    public String TextPhraseBuilder.getResult( )    {       return result.toString( );    }   /**    * Declares a compiler error that gets reported if other classes     * (except Builders or this aspect) try to access the result variable.    */    declare error : (       set(public StringBuffer TextPhraseBuilder +.result)          || get(public StringBuffer TextPhraseBuilder +.result))          && !(within(TextPhraseBuilder +)          || within(TextPhraseBuilderDefaultImplementation)) :           "variable result is aspect protected. use getResult( ) to access it"; }

The TextPhraseDefaultImplementationBuilder aspect provides a default implementation of the getresult() method. This frees the specialized builders from exhausting their single inheritance relationship with an abstract base class. The getresult( ) method provides access to the result field that is also added to the interface and its implementing classes to provide a place to store the result of the builder.

Ideally, the result field would be declared protected since it is only used internally by the TextPhraseBuilder and its subclasses. The AspectJ compiler will not allow protected fields to be introduced on an interface, public is the only option.

This leads to a second problem. How can the pattern's use be constrained so direct access of the public result field is flagged to the developers as the wrong mechanism by which to obtain the fields value? The solution is provided by another powerful feature of AspectJ, the ability to define new compile time checking and error notifications.

Until aspect orientation, the compiler had been a fairly rigid piece of software, not to be tampered with by the developers. However, a few circumstances occur when interaction with the compiler can influence its validation of the code could be useful and this feature is available with AspectJ.

The TextPhraseBuilderDefaultImplementation aspect defines an error to be triggered by the compiler should your code attempt to access the newly added result attribute directly. This will provide a final check that the rules of the pattern are being followed. Although the problem being protected against is a disadvantage of the aspect-oriented implementation of the design pattern, the problem is reduced by incorporating this compile time check.

See Also

Chapter 16 provides specific recipes showing static cross-cutting techniques for extending classes, providing default implementations, and extending the compilers capabilities.



AspectJ Cookbook
Aspectj Cookbook
ISBN: 0596006543
EAN: 2147483647
Year: 2006
Pages: 203
Authors: Russ Miles

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net