Design Pattern Implementation in Java and Aspect J
Design Pattern Implementation in Java and Aspect J
161
These results – 74% of GoF patterns implemented in a more
Screen: Observer
modular way, and 52% reusable – suggest it would be worthwhile
to undertake the experiments of applying AspectJ to more patterns
and/or applying other aspect-oriented techniques to pattern update()
implementations. display(String)
162
Consider a concrete example of the Observer pattern in the 01 public abstract aspect ObserverProtocol {
02
context of a simple figure package, as shown in Figure 1. In such 03 protected interface Subject { }
a system the Observer pattern would be used to cause mutating 04 protected interface Observer { }
operations to figure elements to update the screen. As shown in 05
06 private WeakHashMap perSubjectObservers;07
the figure, code for implementing this pattern is spread across the 08 protected List getObservers(Subject s) {
classes. 09 if (perSubjectObservers == null) {
10 perSubjectObservers = new WeakHashMap();
All participants (i.e. Point and Line) have to know about their 11 }
12 List observers =
role in the pattern and consequently have pattern code in them. 13 (List)perSubjectObservers.get(s);
Adding or removing a role from a class requires changes in that 14 if ( observers == null ) {
15 observers = new LinkedList();
class. Changing the notification mechanism (such as switching 16 perSubjectObservers.put(s, observers);
between push and pull models [9]) requires changes in all 17 }
participating classes. 18 return observers;
19 }
20
4.1.1 The abstracted Observer pattern 21 public void addObserver(Subject s,Observer o){
In the structure of the Observer pattern, some parts are common to 22 getObservers(s).add(o);
23 }
all potential instantiations of the pattern, and other parts are 24 public void removeObserver(Subject s,Observer o){
specific to each instantiation. The parts common to all 25 getObservers(s).remove(o);
26 }
instantiations are: 27
28 abstract protected pointcut
1. The existence of Subject and Observer roles (i.e. the 29 subjectChange(Subject s);
fact that some classes act as Observer and some as 30
Subject). 31
32
abstract protected void
updateObserver(Subject s, Observer o);
2. Maintenance of a mapping from Subjects to Observers. 33
34 after(Subject s): subjectChange(s) {
3. The general update logic: Subject changes trigger 35 Iterator iter = getObservers(s).iterator();
36 while ( iter.hasNext() ) {
Observer updates. 37 updateObserver(s, ((Observer)iter.next()));
38 }
The parts specific to each instantiation of the pattern are: 39 }
40 }
4. Which classes can be Subjects and which can be
Observers. Figure 2: The generalized ObserverProtocol aspect
5. A set of changes of interest on the Subjects that trigger
updates on the Observers
interface. We made this decision based on whether the role
6. The specific means of updating each kind of Observer
interface introduces client-accessed functionality, i.e. exposes
when the update logic requires it.
functionality to clients (as for Strategy, Iterator, etc.) or not (as in
We developed AspectJ code that reflects this separation of the Observer case). If the role has no client-accessible
reusable and instance-specific parts. An abstract aspect functionality, it will only be referenced from within pattern
encapsulates the generalizable parts (1-3), while one concrete aspects. For that reason, we placed it in the abstract aspect. In the
extension of the aspect for each instance of the pattern fills in the other case, we moved the interface into a separate file to make it
specific parts (4-6). The reusable ObserverProtocol aspect easier to reference.
is shown in Figure 2.
4.1.1.2 The Subject-Observer mapping
4.1.1.1 The roles of Subject and Observer Implementation of the mapping in the AspectJ code is localized to
The roles are realized as protected inner interfaces named the ObserverProtocol aspect. It is realized using a weak
Subject and Observer (Figure 2, line 3-4). Their main hash map of linked lists to store the Observers for each Subject
purpose is to allow for correct typing of Subjects and Observers in (line 6). As each pattern instance is represented by a concrete
the context of the pattern implementation, such as in methods like subaspect2 of ObserverProtocol, each instance will have its
addObserver. Concrete extensions of the own mapping.
ObserverProtocol aspect assign the roles to particular
Changes to the Subject-Observer mappings can be realized via the
classes (see below). public addObserver and removeObserver methods (line
These interfaces are protected because they will only be used by 21-26) that concrete subaspects inherit. To have a Screen object
ObserverProtocol and its concrete extensions. No code S become the Observer of a Point Subject P, clients call these
outside the aspect and extensions needs to handle objects in terms methods on the appropriate subaspect (e.g. ColorObserver):
of these roles. ColorObserving.aspectOf().addObserver(P, S);
These interfaces are empty because the pattern defines no methods The private getObservers method is only used internally. It
on the Subject or Observer roles. The methods that would creates the proper secondary data structures (linked lists) on
typically be defined on the Subject and Observer are instead demand (line 8-19). Note that in this implementation the Subject-
defined on the aspect itself (see below).
For patterns that were abstractable we had to decide where to put 2
the role interfaces. Two locations are possible: Either as a private A subaspect is the concrete extension of an abstract aspect, the
interface inside the abstract aspect or as a separate public concept being similar to subclasses in OO languages
163
01 public aspect ColorObserver extends ObserverProtocol { 16 public aspect CoordinateObserver extends
02 17 ObserverProtocol {
03 declare parents: Point implements Subject; 18
04 declare parents: Line implements Subject; 19 declare parents: Point implements Subject;
05 declare parents: Screen implements Observer; 20 declare parents: Line implements Subject;
06 21 declare parents: Screen implements Observer;
07 protected pointcut subjectChange(Subject s): 22
08 (call(void Point.setColor(Color)) || 23 protected pointcut subjectChange(Subject s):
09 call(void Line.setColor(Color)) ) && target(s); 24 (call(void Point.setX(int))
10 25 || call(void Point.setY(int))
11 protected void updateObserver(Subject s, 26 || call(void Line.setP1(Point))
12 Observer o) { 27 || call(void Line.setP2(Point)) ) && target(s);
13 ((Screen)o).display("Color change."); 28
14 } 29 protected void updateObserver(Subject s,
15 } 30 Observer o) {
31 ((Screen)o).display("Coordinate change.");
32 }
33 }
Observer mapping data structure is centralized in each concrete 4.1.2 Pattern-instance-specific concrete aspects
extension. All concrete aspects that subclass the abstract pattern Each concrete subaspect of ObserverProtocol defines one
aspect will automatically have an individual copy of the field.
particular kind of observing relationship, in other words a single
This follows the structure presented in [9]. This can cause a
pattern instance. Within that kind of relationship, there can be any
bottleneck in some situations. These can be fixed, on a per
number of Subjects, each with any number of Observers. The
pattern-instance basis, by overriding getObservers with a
subaspect defines three things:
method that uses a more decentralized data structure.
• The classes that play the roles of Subjects and
Generally, whenever a pattern solution requires a mapping
Observers. This is done using the declare parents
between participants (i.e. the successor field of handlers in Chain
construct, which adds superclasses or super-interfaces to
Of Responsibility) and the pattern implementation is abstractable,
a class, to assign the roles defined in the abstract aspect.
we can either define a field on the participant, or keep the
mapping in a central data structure in the abstract aspect (as in this • The conceptual operations on the subject that require
example). Whichever approach is chosen, the point of access to updating the Observers. This is done by concretizing the
the data structure is the instance-specific aspect, so that different subjectChange pointcut.
instances of the pattern involving the same participants are • How to update the observers. This is done by
possible and will not become confused. concretizing updateObserver. The choice between
4.1.1.3 The update logic push or pull model for updates is no longer necessary as
In the reusable aspect, the update logic implements the general we have access to both the Subject and the Observer at
concept that Subjects can change in ways that require all their this point and can customize the updates.
observers to be updated. This implementation does not define The declare parents construct is part of the AspectJ open
exactly what constitutes a change, or how Observers should be class mechanism that allows aspects to modify existing classes
updated. The general update logic consists of three parts: without changing their code. This open class mechanism can
The changes of interest depict conceptual operations, a set of attach fields, methods, or – as in this case – interfaces to existing
points in program execution, at which a Subject should update its classes.
Observers (to notify them of changes to its state). In AspectJ, sets Figure 3 shows two different instances of the Observer pattern
of such points are identified with pointcut constructs. In the involving the classes Point, Line, and Screen. In both
reusable aspect, we only know there are modifications of interest, instances, Point and Line play the role of Subject, and
but we do not know what they are. Therefore, we define an Screen plays the role of Observer. The first observes color
abstract pointcut named subjectChange that is to be changes, and the second observes coordinate changes.
concretized by instance-specific subaspects (line 28-29).
Note that the type casts in line 13 and 31 are expected disappear
In the reusable part we only know that the Observers will have to with the planned AspectJ support for generics. It will then be
be updated in the context of the pattern, but cannot predict how possible to create parameterized subaspects that incorporate the
that is best achieved. We define an abstract update method role assignment and are type safe.
updateObserver that will be concretized for each pattern
Particular classes can play one or both of the Subject and
instance (line 31-32). That way, each instance of the Observer
Observer roles, either in the same pattern instance or separate
pattern can choose its own update mechanism.
pattern instances. Figure 4 shows a third pattern instance in which
Finally, the reusable aspect implements the update logic in terms Screen acts as Subject and Observer at the same time.
of the generalizable implementation parts mentioned above. This
In the AspectJ version all code pertaining to the relationship
logic is contained in the after advice (line 34-39). This after
between Observers and Subjects is moved into an aspect, which
advice says: whenever execution reaches a join point matched by
changes the dependencies between the modules. Figure 5 shows
the subjectChange pointcut, update all Observers of the
the structure for this case.
appropriate Subject afterwards.
164
01 public aspect ScreenObserver
02 extends ObserverProtocol { ColorObserver
03
04 declare parents: Screen implements Subject; Subject Observer
05 declare parents: Screen implements Observer;
subjectChange
06
07 protected pointcut subjectChange(Subject s):
08 call(void Screen.display(String)) && target(s);
09
10 protected void updateObserver(
11 Subject s, Observer o) {
12 ((Screen)o).display("Screen updated.");
13 }
14 } Point Line Display
Figure 4. The same class can be Subject and Observer
4.1.3 Properties of this implementation Figure 5: The structure of an instance of the Observer
This implementation of the Observer pattern has the following pattern in AspectJ. Subject and Observer roles crosscut
closely related modularity properties: classes, and the changes of interest (the subjectChange
• Locality – All the code that implements the Observer pointcut) crosscuts methods in various classes.
pattern is in the abstract and concrete observer aspects,
none of it is in the participant classes. The participant concretized for each instance of the pattern), which captures the
classes are entirely free of the pattern context, and as a join points that should trigger important events (such as the
consequence there is no coupling between the execution of a Command in the Command pattern). As in the
participants. Potential changes to each Observer pattern Observer example, advice (after, before, or around) is responsible
instance are confined to one place. for calling the appropriate methods.
• Reusability – The core pattern code is abstracted and In the Composite case, to allow walking the tree structure inherent
reusable. The implementation of ObserverProtocol is to the patterns, we define facilities to have a visitor traverse and/or
generalizing the overall pattern behavior. The abstract change the structure. These visitors are defined in the concrete
aspect can be reused and shared across multiple aspect. See Figure 7 for an example of how statistics can be
Observer pattern instances. For each pattern instance, collected from the Composition structure. In this example we
we only need to define one concrete aspect. show an instance of the Composite pattern modeling a file system.
• Composition transparency – Because a pattern Directories are Composites, and files are Leafs. The example
participant’s implementation is not coupled to the shows how to calculate the disk space needed for the file system,
pattern, if a Subject or Observer takes part in multiple assuming that File objects have a size field. Again, clients use
observing relationships their code does not become a public method on the aspect to access the new functionality.
more complicated and the pattern instances are not Appropriate methods on the participants are introduced privately
confused. Each instance of the pattern can be reasoned and are visible only by the aspect.3
about independently. 4.2.2 Singleton, Prototype, Memento, Iterator,
• (Un)pluggability – Because Subjects and Observers Flyweight: aspects as object factories
need not be aware of their role in any pattern instance, These patterns administrate access to specific object instances. All
it is possible to switch between using a pattern and not of them offer factory methods to clients and share a create-on-
using it in the system. demand strategy. The patterns are abstracted (reusable) in
AspectJ, with code for the factory in the aspect.
4.2 Other patterns In the AspectJ implementations, the factory methods are either
In the following we describe the remaining 22 GoF patterns and parameterized methods on the abstract aspect or methods attached
how the AspectJ implementation is different from a pure Java to the participants. If the former approach is used, multiple
version. The patterns are grouped by common features, either of instances of the pattern compose transparently, even if all factory
the pattern structures or their AspectJ implementations. methods have the same names. The Singleton case is special in
that we can turn the original constructor into the factory method
4.2.1 Composite, Command, Mediator, Chain of
using around advice and returning the unique object on all
Responsibility: roles only used within pattern aspect constructor calls.
Similar to the Observer pattern, these patterns introduce roles that
need no client-accessible interface and are only used within the Parameterized factory methods can alternatively be implemented
pattern. In AspectJ such roles are realized with empty (protected) according to Nordberg’s factory example [18]: the factory method
interfaces. The types they introduce are used within the pattern is empty (returns null or a default object). Other return values
protocol. One abstract aspect for each pattern defines the roles are provided by around advice on that method. If the arguments
and attaches default implementations where possible (see Figure 6
for parts of the abstract Composition aspect). 3
Due to a bug in AspectJ release 1.0.6 the private abstract
For patterns involving particular conceptual operations, the introduction of Component.sizeOnDisk() does not work.
abstract pattern aspect introduces an abstract pointcut (to be This is scheduled to be fixed in the next release.
165
public abstract aspect CompositionProtocol { public aspect FileSystemComposite extends
CompositeProtocol {
protected interface Component {}
protected interface Composite extends Component {} declare parents: Directory implements Composite;
protected interface Leaf extends Component {} declare parents: File implements Leaf;
166
of the system without changing all participant classes. This can be Pattern locality should also allow a developer to easily impose
accomplished by attaching methods to the participants using the global policies related to the design patterns, such as adding
open class mechanism. thread safety, logging facilities or performance optimizations.
4.2.6 Façade: no benefit from AspectJ In essence, we observe typical advantages generally associated
with localized concerns with regards to future changes and
implementation program evolution. In particular, the problematic case of pattern
For this pattern, the AspectJ approach is not structurally different composition/overlay [1, 7, 15, 21] becomes better structured (and
from the Java implementation. Façade provides a unified interface easier to reason about) when pattern instances are defined in
to a set of interfaces to a subsystem, to make the subsystem easier separate modular units.
to use. This example mainly requires namespace management and
good coding style. In addition to code-level benefits, the modularity of the design
pattern implementation also results in an inherent documentation
benefit. As mentioned in [1, 21], the mere existence of classes that
5. ANALYSIS exclusively contain pattern code serve as records of what patterns
In this section, we present an analysis of the previously observed
are being used. In the AspectJ cases, we observe two additional
benefits of implementing patterns with AspectJ. The analysis is
improvements. First, all code related to a particular pattern
broken into three parts:
instance is contained in a single module (which defines
• The general improvements observed in many pattern re- participants, assigns roles, etc.). This means that the entire
implementations. description of a pattern instance is localized and does not “get
lost” [21] or “degenerate” [7] in the system. Secondly, with the
• The specific improvements associated with particular current AspectJ IDE support, all references, advised methods etc.
patterns. are hyperlinks that allow a developer an overview of the
• The origins of crosscutting structure in patterns, and a assignment of roles and where the conceptual operations of
demonstration that observed improvements correlate interest are.
with the presence of crosscutting structure in the In 12 cases we were able to develop reusable pattern
pattern. implementations. This happened by generalizing the roles, pattern
code, communication protocols, and relevant conceptual
5.1 General Improvements operations in an abstract reusable aspect. For any concrete
For a number of patterns, the AspectJ implementations manifest instance of the pattern, the developer defines the participants
several closely related modularity benefits: locality, reusability, (assigns roles) and fills in instance-specific code. Changes to
dependency inversion, transparent composability, and communication protocols or methods that are part of the abstract
(un)pluggability. Attempting to say which of these is primary is classes or interfaces involved do not require adjusting all
difficult, instead we simply describe them and discuss some of participants.
their interrelationships.
If we can reuse generalized pattern code and localize the code for
The AspectJ implementations of 17 of the 23 GoF patterns were a particular pattern instance, multiple instances of the same
localized. For 12 of these, the locality enables a core part of the pattern in one application are not easily confused (composition
implementation to be abstracted into reusable code. In 14 of the transparency). The same participating object or class can even
17 we observed transparent composability of pattern instances, so assume different roles in different instances of the same pattern
that multiple patterns can have shared participants (see Table 1). (see the Observer example above). This solves a common problem
The improvements in the AspectJ implementations are primarily with having multiple instances of a design pattern in one
due to inverting dependencies, so that pattern code depends on application.
participants, not the other way around. This is directly related to
locality – all dependencies between patterns and participants are 5.2 Specific improvements
localized in the pattern code. 5.2.1 The Singleton case
An object or class that is oblivious of its role in a pattern can be The AspectJ version of the pattern implementation opened up two
used in different contexts (such as outside the pattern) without design options that are not possible in Java: First, is Singleton an
modifications or redundant code, thereby increasing the inherited property, or do we have an inheritance anomaly?
reusability of participants. If participants do not need to have Second, do we want a devoted factory method to provide the
pattern-specific code, they can be readily removed from or added Singleton instance, or do we want the constructor to return it
to a particular pattern instance, making the participants whenever it is called?
(un)pluggable. To benefit from this, the participants must have a We decided to implement the Singleton property as inherited, but
meaning outside the pattern implementation. For example, the provided facilities to exclude specific subclasses from the
participants in a Chain Of Responsibility pattern often have other Singleton protection if desired.
responsibilities in the application they are in (as widgets in the
GUI example in GoF), while Strategy objects usually just For the second, we decided that using the constructor instead of a
encapsulate an algorithm. devoted factory method was beneficial. The factory, if desired,
can then be implemented either directly in the class, or as a
The locality also means that existing classes can be incorporated transparently composed aspect.
into a pattern instance without the need to adapt them; all the
changes are made in the pattern instance. This makes the pattern
implementations themselves relatively (un)pluggable.
167
Table 1. Design pattern, roles, and desirable properties of their AspectJ implementations
Modularity Properties Kinds of Roles
Composition
Pattern Name Locality(**) Reusability Transparency (Un)pluggability Defining(*) Superimposed
Façade Same implementation for Java and AspectJ Façade -
Abstract Factory no no no no Factory, Product -
Abstraction, -
Bridge no no no no Implementor
Builder no no no no Builder, (Director) -
Factory Method no no no no Product, Creator -
Interpreter no no n/a no Context, Expression -
(AbstractClass), (AbstractClass),
Template Method (yes) no no (yes) (ConcreteClass) (ConcreteClass)
Adapter yes no yes yes Target, Adapter Adaptee
State (yes) no n/a (yes) State Context
Decorator yes no yes yes Component, Decorator ConcreteComponent
Proxy (yes) no (yes) (yes) (Proxy) (Proxy)
Visitor (yes) yes yes (yes) Visitor Element
Command Commanding,
Command (yes) yes yes yes Receiver
Composite yes yes yes (yes) (Component) (Composite, Leaf)
Iterator yes yes yes yes (Iterator) Aggregate
Flyweight yes yes yes yes FlyweightFactory Flyweight
Memento yes yes yes yes Memento Originator
Strategy yes yes yes yes Strategy Context
Mediator yes yes yes yes - (Mediator), Colleague
Chain of Responsibility yes yes yes yes - Handler
Prototype yes yes (yes) yes - Prototype
Singleton yes yes n/a yes - Singleton
Observer yes yes yes yes - Subject, Observer
(*) The distinctions between defining and superimposed roles for the different patterns were not always easy to make. In some cases, roles are
clearly superimposed (e.g. the Subject role in Observer), or defining (e.g. State in the State pattern). If the distinction was not totally clear, the role
names are shown in parentheses in either or both categories.
(**) Locality: “(yes)” means that the pattern is localized in terms of its superimposed roles but the implementation of the remaining defining role is
still done using multiple classes (e.g. State classes for the State pattern). In general, (yes) for a desirable property means that some restrictions
apply
168
Colleague_1 Colleague_2
MediatorPattern
(code) (code) (code)
ConcreteMediator
ConcreteMediator
(code) (code)
Colleague_1 Colleague_3
Colleague_3 Colleague_4
Colleague_3 Colleague_4
(code) (code)
Figure 8: Dependencies and (pattern) code distribution in a typical instance of the Mediator pattern for Java (left) and AspectJ
(right) implementations. The AspectJ implementation removes cyclic dependencies and localizes the pattern code.
5.2.3 Breaking cyclic dependencies have no other behavior of their own. Defining roles often include a
Some design patterns regulate complex interactions between sets of client-accessible interface.
objects. In object-oriented implementations these classes are tightly In other patterns, the roles are superimposed: they are assigned to
coupled and mutually dependent. One example of a design pattern classes that have functionality and responsibility outside the pattern.
that introduces cyclic dependencies is Mediator, a variation of the In the Observer pattern for example, the classes that play Subject
Observer pattern that is often used in UI programming. Here, and Observer do more than just fulfilling the pattern requirements.
changes to Colleagues (e.g. widgets) trigger updates in the Mediator In a GUI context, Subjects could be widgets, for example. In other
object (e.g. director). The Mediator, on the other hand, might update words, classes that have behavior outside the Observer pattern
some or all of the Colleagues as a reaction to this. context. The Subject role is thus only an augmentation of the already
A typical structure for this pattern is shown in Figure 8 (left). existing class. Superimposed roles usually do not have a client-
Inheritance relationships (the Mediator and Colleague interface) are accessible interface.
not shown. The pattern introduces cyclic dependencies between In object-oriented programming, defining roles are often realized by
Mediator and Colleagues (denoted by arrows pointing in opposite subclassing an abstract superclass to achieve different but related
direction). The pattern code (for updates etc.) is distributed both behaviors; superimposed roles are often interfaces that define
over Mediator and all Colleagues. behavior and responsibilities.4
In the AspectJ implementation (Figure 8, right), the indirection 5.3.1 Roles and crosscutting
introduced by the ConcreteMediator aspect removes the cyclic Superimposed roles lead to three different kinds of crosscutting
dependencies. The aspect defines the participants, assigns the roles among patterns and participants:
and identifies which points in the execution trigger updates.
Colleagues do not have to have any pattern-related code in them, • Roles can crosscut participant classes. That is, for 1 role,
they are “freed” of the pattern. Changes to the pattern (for example, there can be n classes, and 1 class can have n roles; i.e. the
the notification interface) are limited to a single module (the aspect). Subject role as shown in Figure 5.
Again, an abstract aspect (here: MediatorProtocol) implements • Conceptual operations of interest can crosscut methods in
generalizable parts of the pattern. one or more classes. That is, for one conceptual operation
there can be n methods, and 1 method can be in n
5.3 Crosscutting structure of design patterns conceptual operations; i.e. the subjectChange
This section presents the origins of crosscutting structure in the operations triggering an Observer update as shown in
patterns and shows that the observed benefits of using AspectJ in Figure 5.
pattern implementation correlate with crosscutting in the pattern.
• Roles from multiple patterns can crosscut each other with
Roles define the behavior and functionality of participants in a respect to classes and/or methods. That is, 2 classes that
pattern. Examples of such roles are Component, Leaf and pattern A sees as part of 1 role, pattern B may see as in
Composite for the Composite pattern, Subject and Observer for the more than 1 role, and vice versa. The same is true for
Observer pattern, or Abstract- and ConcreteFactory for the Abstract conceptual operations; i.e. Subject role and
Factory pattern. Crosscutting in pattern structure is caused by subjectChange operations as shown in Figure 9.
different kinds of roles and their interaction with participant classes.
In some patterns, the roles are defining: the participants have no 4
There is a misalignment in Java in that methods on a
functionality outside the pattern. That is, the roles define the
superimposed role may only be intended for use by the pattern,
participants completely. Objects that play the Façade role, for
but they have to be defined on an interface, which require they
example, provide a unified interface to a subsystem and (usually)
be public.
169
ColorObserver ColorDisplayObserver ColorObserver ColorDisplayObserver
Figure 9: Crosscutting caused by pattern composition. In particular, this figure shows how pattern composition introduces
additional crosscutting by extending Figure 5 with a second pattern instance. The left illustrates how a class can play multiple
roles, while the right shows how mapping points in program execution onto the code crosscuts the participant’s methods.
Table 1 shows that the types of roles a pattern introduces and the This model appears to be accurate for those GoF patterns that
observed benefits of an AspectJ implementation correlate. The have only defining or only superimposed roles. For others, the
design patterns can be divided into three groups: those with only expected benefits seem to depend on the number of participants
defining roles, those with both kinds of roles and those with only implementing a particular kind of role. Superimposed roles that
superimposed roles. The table shows that while the AspectJ map to multiple participants (e.g. Element in Visitor, Composite
implementations of the patterns in first group show no or Leaf in Composite) indicate potential for modularization, even
improvements, patterns from the last group show improvements in if the pattern also includes defining roles.
all modularity benefit categories we identified. For patterns that
have both kinds of roles, the results are dependent on the 6. RELATED WORK
particular pattern. There is a lot of related work focusing either on patterns beyond
Given that AspectJ is intended to modularize crosscutting the GoF patterns, or on issues beyond those in this paper. Note
structure, this result should not be surprising. It says that patterns that since our work focuses on the implementation of existing
that involve primarily crosscutting structure are well modularized design patterns, we do not mention publications dealing with
in an AspectJ implementation. (Note that AspectJ does not finding new patterns. In particular, related work has been done to:
remove the crosscutting of the pattern, but rather provides 1. Investigate pattern applicability in other language
mechanisms to modularize that structure.) paradigms
5.3.2 A predictive model? 2. Automate code generation for patterns, to create a
The tight correlation between pattern roles, the crosscutting a design patterns code library, or to develop tool support
pattern introduces, and the observed benefits of an AspectJ for program design with patterns
implementation suggest a predictive model of the benefit from 3. Classify existing patterns in order to reduce the number
AspectJ implementation of a given design pattern. of distinct patterns or to pinpoint inherent relationships
With defining roles, each unit of abstraction (class) represents a between them
single concept, i.e. the functionality of a class corresponds to its 4. Address the problem of design pattern composition
role in the pattern. Inheritance is used to distinguish between
related but different implementations. In such a case, transparency 5. Enhance the representation of design patterns
and pluggability are not useful properties, as each participant is
inherently useful only within one particular pattern instance.
6.1 Design patterns and language paradigms
Work in this area is directly related to this paper: We investigate
With superimposed behavior, the situation is different. design pattern implementations in AspectJ (AOP) and compare it
Participants have their own responsibilities and justification to implementations in Java (OO).
outside the pattern context. If we force one such class into the
Norvig’s work on design patterns in dynamic programming [19]
pattern context, we have – at the very least – two concerns
explores impacts on the GoF design patterns when implemented
represented by one module of abstraction (class): The original
in Lisp and/or Dylan. This work is another indicator that patterns
functionality and the pattern-specific behavior. The resulting
depend on the language paradigm. Of the 23 patterns, he found
tangling and oftentimes code duplication can cause problems as
that 16 either become either invisible or simpler due to first-class
the modularity is compromised. For these patterns and their
types, first-class functions, macros, method combination,
implementations, a clean modularization of the pattern
multimethods, or modules.
functionality and the original functionalities of the participants is
desirable. In an AspectJ implementation it is usually possible to Sullivan investigated the impact of a dynamic, higher-order OO
modularize the abstracted pattern behavior and have one aspect language (Scheme with a library of functions and macros to
per pattern instance assign roles, conceptual operations, and fill in provide OO facilities) on design pattern implementations [22]. In-
instance-specific code. Since the participants do have a meaning line with Norvig’s work, he observed that some design pattern
outside the pattern context, they are not inherently restricted to a implementations disappear (if language constructs capture them),
single role or even a single pattern instance.
170
some stay virtually unchanged and some become simpler or have and participants in a parameterized form describing the roles and
different focus. which code to inject where. Concrete instance of a pattern are
Nordberg describes how AOP and component-based development created using these descriptions and a special code generator. In
can help in software module dependency management [17]. In a our work, the functionality of the pattern classes are replaced by
different work, he views design pattern improvements from the abstract aspects that encapsulate the roles and pattern behaviors.
point of view of indirections and shows how replacing or Instead of weaving a role-class mapping and the description to
augmenting OO indirection with AOP indications can lead to create code, a concrete aspect is used to assign the roles and to fit
better designs [18]. in appropriate code.
Kühne showed the benefits of combining programming paradigms 6.3 Pattern Classification
via design patterns [12]. In his work, he introduces design Based on our comparison, we classify design patterns according to
patterns to integrate high-level concepts from functional their usage of roles, as this is what we found to affect their
programming in OOP. potential to benefit from an aspect-oriented implementation.
DemeterJ is an adaptive aspect-oriented extension to Java and Various works have addressed the growing number of design
another example of how new language constructs can make design patterns and tried to classify existing patterns according to various
patterns (as described in GoF) disappear. The Visitor design characteristics. Agerbo [1] distinguishes between fundamental
pattern is directly supported in DemeterJ [26]. design patterns (FDPs), and language-dependent design patterns
A few aspect-oriented design patterns have been suggested. For (LDDPs). While FDPs are not covered by any language construct
example, Lorenz’s work describing Visitor Beans, an AOP pattern (in any language), LDDDs have different implementations (or
using JavaBeans [14], or AOP versions of particular design disappear completely) depending on the language used.
patterns as the Command pattern [20]. Gil [10] proposes a similar classification based on the closeness of
patterns to actual language constructs. He identifies three different
6.2 Pattern libraries, parameterized patterns, types of patterns: clichés, idioms, and cadet patterns. Clichés are
and tool support “common uses of prevalent mechanisms” of a particular
Since design pattern descriptions contain information about how programming language, idioms are language mechanisms of non-
the participants interact with each other, what interfaces and mainstream languages, and cadet patterns are “abstraction
variables they have to have, it is only natural to investigate how mechanisms not yet incorporated in any programming language”.
much of the design and code generation process can be We used the reasoning that Façade is more a generally accepted
automated. In many cases, the design patterns “essence” can be mechanism for information hiding (a Cliché in Gil’s terminology)
encapsulated in an abstract aspect and reused. These aspects can than a fully-fledged pattern to explain why it does not profit from
be thought of as a library for patterns, or as library of building an AspectJ implementation.
blocks for systems using design patterns. Zimmer [23] investigated the relationship between patterns in
Budinsky et al. [4] propose a tool for automated code generations pattern compositions. He introduces a three-layer classification of
from design pattern descriptions. Their tool integrates pattern the GoF design pattern based on their potential role in pattern
code into existing systems using multiple inheritance. An compositions. The different categories are “basic design patterns
interesting property of their tool is that it allows for different and techniques” for rudimentary patterns used in others; “design
versions of each design pattern, according to the pattern patterns for typical software problems” for higher-level patterns
descriptions in GoF. Such design choices are dynamically for more specific problems. Finally, “design patterns specific to an
reflected in updated UML diagrams and changed code, so that application domain” is for domain specific patterns. Compared to
developers can see the effects of their choices. our work it appears that patterns that use other patterns in their
solution (i.e. are higher up in the hierarchy) should introduce
In a paper by Florijn et al. [7] a different tool is presented that
more crosscutting than others and profit more form an AspectJ
uses a pattern representation based on so-called fragments (see
implementation. It turns out, however, that the usage of roles is
section 6.5) that allows detecting whether a pattern does not
much more relevant for determining how crosscutting a pattern is.
conform to a particular design pattern “contract” and that can
suggest improvements. 6.4 Roles and pattern composition
A paper by Mapelsden et. al. [15] shows a CASE tool that uses Pattern composition has been shown as a challenge to applying
their design pattern modeling language DPML (see section 6.5). design patterns. In our work, we show how coding design patterns
The tool provides an explicit separation between design patterns, as aspects can solve the modularity problems associated with
their instances, and object models, which a user study found pattern composition.
effective in managing the use of design patterns.
The Role Object Pattern [3] has been introduced to deal with
Alexandrescu’s [2] generic components offer a different approach different requirements imposed on objects in different contexts.
to make design pattern more flexible and reusable. These This approach is an OO attempt to deal with superimposed roles5.
components are reusable C++ templates that are used to create The separation of core functionality and role is realized by
new pattern implementations with little recoding. In [21], Soukup introducing role object fields into the core classes, which
describes a C++ library of reusable pattern implementations, themselves share a high-level interface with the role classes. This
which uses an approach quite similar to ours. To avoid invasive
changes to existing classes, “pattern classes” are introduced, 5
which are encapsulations of the pattern role implementations. In that the core classes already have defined responsibility and
These classes include pattern code and a description of the pattern the role introduces additional responsibilities.
171
creates cyclic references: ComponentCore stores a list of roles, The improvements manifest themselves as a set of properties
and each ComponentRole has a reference to the core object related to modularity. The pattern implementations are more
they are attached to. While introducing tight coupling between localized, and in a number of cases are reusable. Because the
core and role, this approach enables dynamically adding and AspectJ solutions better align dependencies in the code with
removing roles from an object. Fowler [8] presents guidelines on dependencies in the solution structure, AspectJ implementations
different variations of the pattern and when to use them. of the patterns are sometimes also composable.
Other work describes different approaches to model roles and Localizing pattern implementation provides inherent code
their relationship to the concrete classes playing those roles. comprehensibility benefits – the existence of a single named unit
Mikkonen [16] formalizes them as behavioral layers (object of pattern code makes the presence and structure of the pattern
slices). Florijn et. al. [7] introduces a fragment model (see below) more explicit. In addition, it provides an anchor for improved
that represents participant roles as a particular kind of fragments. documentation of the code.
Mapelsden et. al [15] differentiate explicitly between patterns, Our results suggest several directions for further experimentation,
their instances, and object models. Their graphical notation including applying AspectJ to more patterns, attempting to make
(DMPL) allows mapping roles to concrete classes. Design pattern systematic use of our reusable pattern implementations, and
libraries and code generators usually introduce a means to assign attempting to use AspectJ in legacy code bases that are known to
pattern roles to concrete classes. The most commonly used tools be influenced by design pattern thinking. Another avenue for
to weave role-related code into existing classes are multiple future work is to compare these results with the use of other
inheritance [1, 4, 16], or a dedicated weaver [21]. aspect-oriented techniques.
6.5 Alternative pattern representations 8. ACKNOWLEDGEMENTS
This area is remotely related in that it outlines new approaches to Our thanks go to Gail Murphy and the anonymous reviewers for
design pattern notation. their helpful comments on earlier versions of this paper.
A number of papers address problems with the preciseness of the
pattern description format presented in GoF. Lauder and Kent 9. REFERENCES
[13] introduce a hierarchical model (consisting of three layers [1] Agerbo, E., Cornils, A. How to preserve the benefits of
based on UML notations) for describing pattern structures and Design Patterns. Proceedings of OOPSLA 1998, pp. 134-143
dynamic behavior. The role model captures the “pure pattern”,
and is refined by a type-model (similar to the GoF UML [2] Alexandrescu, A. Modern C++ Design: Generic
diagrams), which is in turn refined by an instance-specific model Programming and Design Patterns Applied. Addison-
that uses the concrete names a particular pattern instance. The Wesley, 2001
authors claim that the three models complement each other and [3] Bäumer, D., Riehle, D., Siberski, W., and Wulf, M. Role
that a developer should have access to all three models of a Object Pattern. Proceedings of PLoP '97. Technical Report
particular pattern. WUCS-97-34. Washington University Dept. of Computer
Florijn et. al. [7] suggest a fragment-based representation of Science, 1997
design patterns. A fragment depicts a design element such as a [4] Budinsky, F., Finnie, M., Yu, P., Vlissides, J. Automatic
class, method or association). Patterns themselves and all code generation from Design Patterns. IBM Systems Journal
elements in a pattern instance (classes, relationships among them, 35(2): 151-171
code) are represented as (graphs of) fragments.
[5] Coplien, J. O. Idioms and Patterns as Architectural
Mapelsden et. al. [15] introduce the design pattern modeling Literature. IEEE Software Special Issue on Objects, Patterns,
language DPML, built upon similar concepts as UML. This multi- and Architectures, January 1997
level approach (design patterns, pattern instances, and object
models) makes it possible to show objects and their roles within [6] Coplien, J. O. Software Design Patterns: Common Questions
the pattern. and Answers. In: Rising L., (Ed.), The Patterns Handbook:
Techniques, Strategies, and Applications. Cambridge
Mikkonen [16] addresses the problem that the temporal behavior
University Press, NY, January 1998, pp. 311-320
of design patterns is difficult to reason about and proposes a
formal notation for this purpose. This model formalizes patterns [7] Florijn, G., Meijers, M., Winsen, P. van. Tool support for
as behavioral layers, and realizes the interactions between objects object-oriented patterns. Proceedings of ECOOP 1997
as atomic actions. With this approach, pattern compositions can
[8] Fowler M.: Dealing with roles. Proceedings of PLoP '97.
be modeled.
Technical Report WUCS-97-34. Washington University
7. SUMMARY Dept. of Computer Science, 1997
Improvement from using AspectJ in pattern implementations is [9] Gamma, E. et al. Design Patterns – Elements of Reusable
directly correlated to the presence of crosscutting structure in the Object-Oriented Software. Addison-Wesley, 1994
patterns. This crosscutting structure arises in patterns that
[10] Gil, J., Lorenz, D. H. Design Patterns vs. Language Design.
superimpose behavior on their participants. In such patterns the
ECOOP 1997 Workshop paper
roles can crosscut participant classes, and conceptual operations
can crosscut methods (and constructors). Multiple such patterns [11] Kiczales, G., Lamping, J., Mendhekar, A., Maeda, C., Lopes,
can also crosscut each other with respect to shared participants. C., Loingtier, J.-M., and Irwing, J. Aspect-Oriented
172
Programming. Proceedings of ECOOP ’97, Springer Verlag, [19] Norvig, P. Design Patterns in Dynamic Programming. In:
pages 220-242, 1997 Object World 96, Boston MA, May 1996
[12] Kühne, T. A Functional Pattern System for Object-Oriented [20] Sletten, B. Beyond Actions – A Semantically Rich Command
Design. Ph.D. Thesis, Darmstadt University of Technology, Pattern for the Java™ Foundation Classes (JFC/Swing) API.
Verlag Dr. Kovac, ISBN 3-86064-770-9, July 1999 Presentation at JavaOne 2002
[13] Lauder, A., Kent, S. Precise Visual Specification of Design [21] Soukup, J. Implementing Patterns. In: Coplien J. O.,
Patterns. Proceedings of ECOOP 1998 Schmidt, D. C. (eds.) Pattern Languages of Program Design.
[14] Lorenz, David H. Visitor Beans: An Aspect-Oriented Addison Wesley 1995, pp. 395-412
Pattern. ECOOP 1998 Workshops, pages 431-432, 1998 [22] Sullivan, G. T. Advanced Programming Language Features
[15] Mapelsden, D., Hosking, J. and Grundy, J. Design Pattern for Executable Design Patterns. Lab Memo, MIT Artificial
Modelling and Instantiation using DPML. In Proceeding of Intelligence Laboratory, number AIM-2002-005, 2002
TOOLS Pacific 2002, Sydney, Australia. Conferences in [23] Zimmer, W. Relationships Between Design Patterns. In:
Research and Practice in Information Technology, 10. Noble, Coplien, J. O., Schmidt, D. C. (eds.) Pattern Languages of
J. and Potter, J., Eds., ACS Program Design. Addison-Wesley, 1995, pp. 345-364
[16] Mikkonen, T. Formalizing Design Patterns. Proceedings of [24] The AspectJ user mailing list.
ICSE 1998, pp. 115-124 http://aspectj.org/pipermail/users/
[17] Nordberg, M. E. Aspect-Oriented Dependency Inversion. [25] The AspectJ web site. http://www.aspectj.org
OOPSLA 2001 Workshop on Advanced Separation of
Concerns in Object-Oriented Systems, October 2001
[26] The DemeterJ web site.
http://www.ccs.neu.edu/research/demeter/DemeterJava/
[18] Nordberg, M. E. Aspect-Oriented Indirection – Beyond
Object-Oriented Design Patterns. OOPSLA 2001 Workshop
[27] The Java web site. http://www.java.sun.com
"Beyond Design: Patterns (mis)used", October 2001
173