4. Related Work
When the only tool you have is a hammer,
everything looks like a nail.
Abraham Maslow

The connection between design patterns and programming languages has been debated since the "Gang of Four" patterns were published. In this chapter, we discuss selected studies regarding application of the "Gang of Four" patterns using specific languages, as well as how different features may help provide simpler implementations or even components. The level of language support for a given pattern will influence the implementation because it determines how much work is required to apply the pattern. We focus on both dynamic and static languages as we consider Java 6 a hybrid: though static, its special language mechanisms and runtime capabilities allow Java to exhibit very dynamic behaviour at runtime. We compare the different studies and relate the observations to issues deemed relevant for Java 6. As always, a summary concludes this chapter.

The choice of language will affect the pattern application because the language will ultimately decide what can and what cannot be done (easily) in light of supported programming paradigms [Gamma95, p.4]. Several studies have been undertaken to investigate "Gang of Four" pattern application in various programming languages. This chapter discusses studies of implementations in dynamic languages like Common Lisp, Dylan, and Scheme, and in static languages like C++, Java, Java + AspectJ, and Eiffel. Common features used in the various studies as well as discovered common pattern behaviour are compared in section 4.4, but this is not an easy task as the studies have different focus. We start by establishing the level of support a given language has for a given pattern.

4.1.  Language Support
The traditional close connection between design patterns and statically typed languages is criticised by some, mainly because static languages often lack advanced runtime constructs. The "human compiler" is put to work, repeatedly writing Meta—programs, e.g. patterns, to cope with the missing (runtime) features [Graham02]. Even more specific, some believe the "Gang of Four" design patterns are simply a library of C++ code templates [Dominus02; PPR, p.DesignPatternsInDynamicProgramming]. However, such claims seem to neglect that several of the "Gang of Four" patterns were exemplified using Smalltalk that has advanced runtime features, including dynamic typing and reflection. The patterns are still relevant even if implemented in Smalltalk. Still, others regard traces of the "Gang of Four" patterns in the source code as code smells; an indication of the language used is not powerful enough and/or developers blindly using design patterns [Halloway07]. This view assumes that the entire pattern abstraction can be represented as language features. The point is moot as already discussed in section 3.9 because like any other tool, design patterns should be used only when the design merits it. Furthermore, we have yet to a see a language that has built—in support for all the "Gang of Four" patterns.

At [PPR, p.AreDesignPatternsMissingLanguageFeatures], it is discussed whether a pattern stops being a pattern in the context of a language that has some kind of built—in support for it. The discussion concerns the verbal use of the term pattern and as well as its meaning. There is no definitive conclusion presented, but it is suggested that design patterns are one way programming languages can evolve. The consensus seems to be that a pattern does not stop being a pattern because a given language has support for it, but that designers stop referring to it explicitly as a pattern, effectively altering the common vocabulary of patterns for the given domain. From this follows that developers will stop referring to the pattern description as well; therefore, we conclude, the ultimate consequence must then be that when all programming languages implement a given pattern, or have support for it as a component, there will no longer be use for its description. These issues indicate a very strong connection between patterns and languages, but one that may eventually be discarded. Meyer calls this the Pattern Elimination Conjecture: any useful pattern should in the long term be discarded as a pattern, and replaced by reusable components with a clear, simple, directly usable interface [Meyer03, p.41]. This corresponds well with the efforts being made regarding pattern formalism as described in section 3.6 at the expense of human interaction in the application process.

4.1.1.  Implementation Level
In [Norvig96], Norvig classifies the level of implementation a pattern can have in a given programming language as paraphrased in table 4.1 below. Built—in support for a pattern thus corresponds to either Invisible or Formal if part of the standard libraries, while Informal corresponds to Alexander's view on pattern application.

Table 4.1PrintTable 4.1 — Pattern implementation level (modified from [Norvig96, p.7])
LevelDescriptionJava 6 Example
InvisibleA pattern is so much a part of the language that its usage is not noticed by the user.The for—each loop help hide explicit usage of the Iterator pattern.
FormalA pattern is implemented in a language, but must be instantiated or called for each use (component).The Iterator pattern can still be explicitly implemented and/or used.
InformalA pattern is part of a common shared vocabulary and referred to by name, but must be implemented from scratch for each use based on its description.The Singleton pattern must be implemented for each relevant class.

Note, that even though a pattern is invisible on average use does not mean that it cannot be used formally. Invisible and Formal does not exclude a pattern from a common vocabulary or from being implemented alternatively either, e.g. Informally. The classification is rather subjective because different users may notice different things, depending on their point of view: an API developer may need to create different Iterator implementations, but the API user may not need to. In our view, the distinction between Invisible and Formal is vaguely defined, whereas it is easier to distinguish between Formal and Informal.

As summarised in the section 4.2.1, Norvig implements the "Gang of Four" patterns in Common Lisp and Dylan and arrives at "simpler" implementations. At [PPR], Norvig's simpler implementations of the "Gang of Four" patterns are seen as augmenting Graham's critique about the "human compiler" at work. However, while Norvig is in agreement with Graham in using certain dynamic features to implement functionality, Graham is directly criticising the concept of design patterns. By using a proper language, says Graham, the need for design patterns is non—existent. We disagree, and to our understanding, so does Norvig, Meyer [Meyer03, p.41], and [PPR].

4.1.2.  Discussion
In our view, the validity of a design pattern is not lessened because a given language has full, partial, or just easier support for it. The knowledge represented by a design pattern should ideally be independent of any specific programming language, what Norvig calls Programming Into a language [Norvig96, p.58] as already described in section 2.5. Lea states that a pattern is not an implementation, but instead describes when, why, and how to go about creating an implementation or other engineering product [Lea00, i.6]. We believe the danger of equalising design patterns with the implementation is forgetting that the human factor is paramount in understanding and applying design patterns in different contexts, which is exactly what makes design patterns a very flexible tool indeed. On the other hand, the ease and practicality of using design patterns is also important. For example, nobody wants to implement the Iterator pattern for each system. In Java, the Java Collections framework is used. In Java, however, everybody has to implement the Singleton pattern for each applicable class because the language does not support the abstraction described by the pattern (which Java actually in part does, as discovered during the evaluation and explained in section Hence, the sheer practicality in the frequent application of certain simple design patterns in our view warrants Formal and/or Invisible implementations, respectively componentization and/or language support. Even though Coplien is in favour of pattern componentization [Coplien, i.3], he equalises the human factor (still required) with creativity and claims it will always be needed [Coplien, i.11]. Along these lines, Fowler argues that patterns are needed because real—world solutions have failed despite using the latest technology for lack of ordinary solutions. Patterns provide a way to organise and name those ordinary solutions to make it easier for ordinary people to use them [Fowler06]. This is contrary to Graham's claim of design pattern usage being "institutionalised" [Graham02], especially considering no standard formalisation of patterns has been agreed upon as discussed in section 3.6.

Practical pattern implementation, however, is dependent on the pattern granularity. A pattern can be applied across systems, but also within systems. Typically, architectural design patterns, having large granularity, are applied once per system, for example the Two—Tier Architecture pattern from example 2.3. We find it reasonable to assume their level of granularity and abstraction will make them difficult to componentize compared to the "Gang of Four" patterns with finer granularity. Therefore, they must be adapted to the system at hand. Hence, it is also unlikely they will evolve into language features. Ergo, they will not cause duplicate code. Conversely, the "Gang of Four" design patterns describe problems and solutions that are so common they occur in many different contexts with relatively fine granularity within the same system. It is unreasonable to assume that such patterns, for example Iterator, would be applicable only once in a system, even more so for idioms as they are very tightly connected to a given programming language.

On the other hand, even some "Gang of Four" patterns like Facade and Template Method pose problems because of abstraction and granularity level. Hence, componentization and language support in form of Formal and Invisible patterns, respectively, can augment reuse, but patterns that for one reason or another remain Informal still generate specific implementations for each usage even within the same system. We consider the Singleton pattern the archetypal example of this in Java. This raises the issue if Informal design patterns collide with the principles of OO as discussed at [PPR]. In our view, this is not the case. Each application of the pattern will cause an implementation targeted for a specific problem in a specific context within the system. Two different contexts will thus cause two different implementations, albeit similar. Common functionality can still be factored out. What appears as duplicate code is in reality not; the true semantics come from the pattern description combined with the specific adaptation. In Alexander's domain, a house could be an analogy to an OO system: is it unreasonable to assume that within a given house, a "window pattern" can be applied more than once? Obviously not, and this results in duplicate functionality. In case the design of a window is discovered to be flawed, for example if the glass does not provide sufficient insulation, all windows have to be repaired or replaced eventually. Still, the alternative is surely not to apply the pattern only once.

We believe the success of componentizing a given pattern into a language or library depends perhaps more so on its abstraction and granularity level than the language in which it is implemented. It is possible, though, that the language will dictate behaviour that makes componentization difficult, if not impossible. While the human factor is important in understanding and applying patterns, we still think simple design patterns should be componentized, if possible; or even better evolve into language features.

4.2.  Dynamic Languages
The studies by Norvig [Norvig96] and Sullivan [Sullivan02a; Sullivan02b] emphasise that dynamic features of Common Lisp, Dylan, and Scheme, respectively, have a large impact in providing simpler implementations. However, we cannot find a standard precise definition of what a dynamic language is or what it must support. A generalisation is that a dynamic language possesses one or more of the following overall features: dynamic typing, runtime code modification, and interpretation [Hacknot07]. Dynamic typing (or dynamic type binding) enforces type rules at runtime as opposed to compile—time. The type of a variable is not determined until the variable is actually used at runtime [Sethi96, p.137]. Runtime code modification allows changes to the structure of executing code, for example adding new methods to an object. Interpretation is the process of reading and evaluating program code at runtime without prior compilation; an interpreter runs the program directly [Sethi96, p.20]. It is also worth noting that Common Lisp, Dylan, and Scheme all are functional languages.

4.2.1.  Common Lisp and Dylan
Not long after the "Design Patterns" book was published, Norvig showed that sixteen of the twenty—three "Gang of Four" patterns have qualitatively simpler implementation in Common Lisp or Dylan compared to C++ for at least some uses of each pattern [Norvig96, p.9]. Common Lisp and Dylan are dynamic languages, and many of the language features found in dynamic languages are exactly what makes the pattern application simpler, such as first—class types [Norvig96, p.10]. Table 4.2 illustrates the specific features Norvig found that influenced specific "Gang of Four" patterns.

Unfortunately, Norvig does not directly apply his implementation level classification to the "Gang of Four" patterns, nor does he discuss why seven patterns cannot be made simpler in dynamic languages. Though note that four of them are Structural patterns, i.e. Adapter, Bridge, Composite, and Decorator, two are Creational, i.e. Prototype and Singleton, and only one is Behavioural, namely Memento. At first, this seems to make sense: dynamic languages are all about runtime behaviour whereas Structural patterns represent (static) structure. However, the ability to perform runtime code modification would seem to affect at least Adapter, and Decorator is an ideal candidate for method combination. Furthermore, the two Creational patterns would be almost directly supported in prototype—based languages, which Common Lisp and Dylan are not; Common Lisp utilises CLOS for OO capabilities (e.g. multiple—dispatch), and Dylan utilises built—in classes.

Table 4.2PrintTable 4.2 — "Gang of Four" patterns in Common Lisp and Dylan (modified from [Norvig96, p.10])
FeatureDescription"Gang of Four" patterns
First—class typesTypes can be used without restrictions and are treated as any other (first—class) object, i.e. can be constructed at runtime, stored in variables, have identities, etc. [Norvig96, p.11].Abstract Factory, Chain of Responsibility, Factory Method, Flyweight, Proxy, State
First—class functionsA first—class function is a first—class object, and can for example be created at runtime [Norvig96, p.14].Command, Strategy, Template Method, Visitor
MacrosMacros provide syntactic abstraction [Norvig96, p.17].Interpreter, Iterator
Method combinationCombination of methods having the same signature to execute in a given order [Sullivan02a, p.9]. Enforced by the language as in CLOS or explicitly, e.g. using the Extend Super pattern (see section 3.8.2).Mediator, Observer
Multi—methods (multiple—dispatch, generic function)In multiple—dispatch, methods are grouped based on their name into multi—methods, and the correct method to invoke is determined based on all the arguments [Sullivan02a, p.8-9].Builder
ModulesA module explicitly encapsulates data and operations [Sethi96, p.209]. May also represent namespaces [Norvig96, p.28].Facade
Not discussedAdapter, Bridge, Composite, Decorator, Memento, Prototype, Singleton

Some understand Norvig's work as a criticism of design patterns, but in our view, Norvig is not criticising the concept of design patterns, merely stressing the impact of the programming language, advocating the use of dynamic languages. Norvig even suggests several other pattern variants for dynamic languages as well [Norvig96, p.31]. He states that design patterns are higher—order abstractions for program organisation that help discuss, weigh, and record design trade—offs [Norvig96, p.4].

4.2.2.  Scheme
In [Sullivan02a] and [Sullivan02b], Sullivan studies if language features can move design patterns away from the Informal implementation level into the Invisible or Formal levels; that is, how the basic capabilities of reflection and dynamism affect the need for, use of, and implementation of the "Gang of Four" design patterns. To try to establish a connection between modelling and programming languages, Sullivan investigates how languages can enable more abstraction in a declarative style, i.e. abstraction expressed using language constructs, for example in form of multi—methods. Sullivan emphasises the need for modelling as models enable abstraction, are declarative in style, and can allow for pre—runtime verification, but warns that dynamic features make it more difficult to analyse program statically [Sullivan02b, p.3,35]. As the language, Scheme is used with the GLOS library that adds certain OOP facilities. Sullivan reasons that reflection is closely related to first—class values as reflection refers to the ability of a program to reason about its own structure and behaviour [Sullivan02a, p.3]. Table 4.3 summarises the outcome of Sullivan's investigations based on the summaries for each investigated pattern in [Sullivan02a]. It illustrates which features where useful in a given pattern implementation, and there is a large overlap with the features discussed by Norvig from table 4.2.

Table 4.3PrintTable 4.3 — "Gang of Four" patterns in Scheme + GLOS
FeatureDescription"Gang of Four" patterns
First—class typesSee table 4.2.Abstract Factory, Builder, Prototype
First—class functionsSee table 4.2.Adapter, Builder, Chain of Responsibility, Command, Iterator, Mediator, Strategy
MacrosSee table 4.2.Proxy
Method combinationSee table 4.2.Decorator, Proxy, Memento
(multiple—dispatch, generic functions)
See table 4.2.Abstract Factory, Adapter, Builder, Chain of Responsibility, Factory Method, Mediator, Observer, Strategy, Visitor
ModulesSee table 4.2.Adapter
ReflectionReflection refers to the ability of a program to reason about its own structure and behaviour [Sullivan02a, p.3].Abstract Factory, Prototype, Chain of Responsibility, Memento
Instantiation protocolsControls how objects are created, either explicitly or implicitly (hidden or built—in).Factory Method, Singleton, Flyweight, Proxy
Singleton typesA type that matches exactly one value [Sullivan02a, p.6], e.g. an instance of java.lang.Class in Java.Abstract Factory, Factory Method, Proxy
Predicate typesPredicate types are based on predicate functions and thus resolved at runtime [Sullivan02a, p.9].State
ClosuresA closure consists of an expression (function) and its saved environment [Sethi96, p.534].Command, Flyweight, Iterator, Strategy
Prototype—basedHas no notion of classes. Behaviour reuse is achieved by cloning existing objects that act as prototypes.Prototype, State
None (similar)Bridge (universal), Composite, Facade (universal), Interpreter, Template Method (universal)

In accordance with Norvig, Sullivan concludes that dynamic features such as reflection, multiple—dispatch, higher—order functions, and predicate types have a positive impact on nearly all of the "Gang of Four" patterns [Sullivan02a, p.43]. Underlined patterns in the table above represent similar usage by Norvig. Instantiation and method protocols are also effective [Sullivan02b, p.34]. Sullivan states that the need for explicit patterns may disappear or the implementation may become much simpler, but mention that the Scheme implementations do not always capture the entire pattern functionality. Emphasis is clearly on the implementation aspect at the expense of pattern abstraction. Factory Method and Singleton, for example, are described as easily implemented in any language supporting an extensible instantiation protocol, but C++ already supports modification of the instantiation protocol by overloading new [Stroustrup91, p.215]. This indicates that the patterns describe more than code. Command and Strategy are implemented using closures, but closures do not capture the abstraction of an object with additional functionality, i.e. extra functionality, polymorphism, identity, etc. Just because a language supports a given feature does not mean the feature is the pattern by itself. What it does mean is that the feature in certain cases can represent the pattern implementation in the language in question.

Comparing the results from Sullivan and Norvig, it puzzles us that Norvig only lists the patterns as utilising a single feature. It is probably for educational or practical purposes, i.e. listed according to primary exploited feature. We think this is why there is little overlap in features for the individual patterns (underlined patterns in table 4.3), while the overall conclusions are the same. Unfortunately, it makes it hard to conclude anything based on Norvig's study. Sullivan is more detailed, and several of the patterns not covered by Norvig are addressed, for example Adapter, Decorator, Prototype, and Singleton. Sullivan's conclusion, however, comes as no surprise as Scheme is closely related to Lisp. Like Norvig, Sullivan accedes that the "Gang of Four" patterns are closely related to design and modelling as the patterns discuss design trade—offs. Even more so, certain patterns represent universal programming concepts that cannot be solved with language features alone [Sullivan02a, p.43; Sullivan02b, p.36].

4.3.  Static Languages
C++ and Java are statically typed languages. Type errors are detected at compile—time. The advanced features discussed by Gamma et al. for the "Gang of Four" implementations all but a few exclusively targets Smalltalk, which uses dynamic typing.

4.3.1.  C++
The "Gang of Four" patterns all supply implementation or sample code in C++. The features used are those presented in the Implementation and Sample Code pattern elements in [Gamma95]. Gamma et al. primarily use C++ constructs found commonly elsewhere as well, e.g. classes, inheritance, access modifiers, etc., but more exotic features like templates, multiple inheritance, friends, overloaded operators are also utilised. These features are not found in Java 6, and hence alternative ways to implement the pattern in question must be applied.

4.3.2.  Java
All the "Gang of Four" design patterns have been implemented in at least Java 1.2, 1.3, and 1.4, some even at an Invisible implementation level as exemplified in section 2.6.2. Many different Java implementations of individual "Gang of Four" patterns exist. Grand, for example, presents almost exact Java 1.2 versions of all the "Gang of Four" design patterns in [Grand98; Grand99], and Hannemann et al. have implemented pure, albeit very simple, Java 1.4 versions used for comparison with the AspectJ implementations discussed next [Hannemann02]. Another example is [Eckel03], where some of Java's more advanced features such as reflection and dynamic proxies are used. However, the implementation level of the individual patterns is primarily Informal, and we know of no efforts to componentize the "Gang of Four" patterns in Java 5 or 6.

Hence, all "Gang of Four" patterns are known to be applicable in Java. This is expected as Java adheres to the fundamental OO concepts and can directly express many of the themes discussed by Gamma et al. Java is not considered a dynamic language, but it still possesses advanced runtime features like reflection and dynamic class loading. Bearing Norvig and Sullivan's work in mind, we therefore assume that the practical application will be easier and/or present alternatives to the canonical C++ implementations. On the other hand, runtime features in class—based languages often yield verbose source code, which could imply more work, and possibly clutter the core functionality and intent of the pattern when reviewing the source code. Reusable libraries and components, however, can shield the pattern implementations from much of this.

4.3.3.  Java and AspectJ
Sullivan notes that crosscutting concerns of Aspect—Oriented Programming (AOP) matches well design patterns because patterns are primarily concerned with the coordination of multiple "parts" of a system, typically via classes and abstract methods [Sullivan02a, p.3]. Patterns are the glue that connects the joints [Sullivan02b, p.6]. Hannemann et al. have shown this in practice by implementing the "Gang of Four" patterns in Java 1.4 and AspectJ [AspectJ], claiming that seventeen of the twenty—three implementations exhibit modularity improvements in terms of better code locality, reusability, composibility, and (un)pluggablity. The improvements vary, but with the greatest improvement coming when the pattern solution structure involves crosscutting concerns, e.g. a one object playing multiple roles, many objects playing one role, or an object playing roles in multiple pattern instances [Hannemann02, p.1]. Besides locality and reusability, and following code—level benefits, Hannemann et al. state that modular pattern implementations ensure that the entire pattern description of a pattern instance is localised and does not "get lost" or "degenerate" in a system as could otherwise pose a problem [Hannemann02, p.7]. Twelve of the implementations constitute reusable components with respect to abstract aspects [Hannemann02, t.1].

AspectJ uses aspects to encapsulate crosscutting concerns in one place. They can apply additional behaviour, or advice, to various joint points, for example constructors or methods. Joint points are specified using pointcuts, either directly or in form of a "query" to detect if a given joint point matches the aspect based on signatures. Furthermore, to encapsulate all code related to a given concern in a single aspect, the open class mechanism might be used to declare members or parents of another class. For a full introduction to AspectJ, see [AspectJ]. Table 4.4 lists the different AspectJ features used to improve the various "Gang of Four" implementations.

As expected, the dynamic features of AspectJ are what facilitate easier implementations. Advice is equivalent to the method combination features found in CLOS and GLOS, clearly illustrated in the ability to execute the contained code before, after, and around join points, though advice cannot be added or removed at runtime [Sullivan02a, p.20]. Hannemann et al. utilise this feature extensively, for example to intercept calls to new for Singleton classes, thereby creating a specific instantiation protocol. Pointcuts can be seen as macros. In pure Java, the reflection mechanism does not allow for structural changes to classes or objects, only behavioural ("read—only"). By exposing the structure of the executing program as objects, for example the java.lang.Class and java.lang.reflect.Method classes representing a class and a method, respectively, such objects can be accessed like any other first—class object. In AspectJ, however, the open class mechanism is a work—around to modify Java's otherwise static classes, approaching true first—class behaviour. AspectJ still adheres to the standard Java semantics, which gives certain static advantages such as compile—time type errors. Some errors are still only seen at runtime, for example if a given pointcut does not capture a jointpoint as expected.

Table 4.4PrintTable 4.4 — "Gang of Four" patterns in Java + AspectJ
FeatureDescription"Gang of Four" patterns
Roles only used within pattern aspectAbstract aspect per pattern defines the roles and default implementations where possible, local to the pattern realisations. Abstract pointcuts specify hooks for additional specialisation [Hannemann02, p.5].Chain of Responsibility, Composite, Command, Mediator, Observer
Aspects as object factoriesPatterns are abstracted into aspects containing code for the factory functionality; the factory methods used are contained either in the abstract aspect or in the participants [Hannemann02, p.5].Flyweight, Iterator, Memento, Prototype, Singleton
Language constructsPattern implementations are directly affected by language constructs such as the open class mechanism or by attaching advice [Hannemann02, p.6].Adapter, Decorator, Proxy, Strategy, Visitor
Multiple inheritancePattern implementations can implement any number of interfaces and use the open class mechanism to attach default functionality [Hannemann02, p.6].Abstract Factory, Factory Method, Bridge, Builder, Template Method
Scattered code modularisedAttaching advice to be break tight coupling between participants [Hannemann02, p.7].Interpreter, State
None (similar)Facade

Some of the implementations in AspectJ result in a completely new design structure. We find it difficult to identify the actual role Java occupies in this study as opposed to specific AspectJ features. Most of the Java features used in the implementations are trivial, such as classes and interfaces. Very few advanced features such as inner classes and weak references are used. The pattern functionality is achieved with the AspectJ features, which may mimic C++ features such as multiple inheritance and private (functional) inheritance.

By using Java's built—in reflection mechanism and annotations as of version five, we believe much of the same dynamic functionality could be achieved without the use of AspectJ, though at some expense. Classes could implement advice functionality that can be attached to any accessible object (jointpoint), i.e. field, constructor, or method. Pointcuts could be specified by annotations. Unfortunately, all access to enriched objects must go through proxy objects to intercept invocations to apply the advice, but it would allow the advice to change at runtime. This indicates a need for a framework to handle the execution. Furthermore, as reflection would be utilised extensively, runtime errors are in effect unavoidable, but probably manageable. It reminds us of existing products using similar ideas, such as Hibernate, JBoss Seam, or Google Guice. In any case, in accordance with Sullivan's conclusions, Java's reflection mechanism could have a significant impact on the "Gang of Four" pattern implementations as most are exemplified using C++ that has few runtime features.

4.3.4.  Eiffel
In section 2.6.2, we discussed how patterns could aid in the implementation phase during OO development. Options are adaptation and application, componentization, and language support, corresponding with Norvig's implementation levels Informal, Formal, and Invisible, respectively. Using Eiffel as the programming language, Meyer and Arnout claim to provide full componentization for eleven of the "Gang of Four" patterns and partial componentization for an additional four [Meyer06, p.3], totalling two thirds of the patterns. Full componentization is defined by Meyer and Arnout to include all the original pattern functionality [Meyer06, p.2] and is equivalent to what Norvig calls first—class patterns [Norvig96, p.31]. Their implementation level is Formal because as components they can be treated like any other object [Norvig96, p.32], or Invisible as part of the language. Componentization is an effective way to avoid duplicate code as discussed in section 3.9.1. It is more difficult than ad—hoc pattern application as examined by Norvig and Sullivan, however, because it focuses extensively on reusability. The focus of Meyer and Arnout is closer to pure Java 6 implementations compared to the AspectJ implementations by Hannemann et al., because their components rely on reusable classes, not reusable aspects [Arnout06]. Furthermore, the specific Eiffel features utilised in the components are described in [Arnout06, t.1].

Examples of full componentization achieved by Meyer include Composite, Command, Abstract Factory, and Visitor [Meyer06, p.10-11]. Six patterns required some form of automated support to help integrate them into libraries through reusable skeletons, or though components that address part of the problem. Only two patterns could not even be partially componentized or handled through some automated support, namely Facade and Interpreter; Facade is obvious, because it is completely dependent on the context and abstraction used, it seems universal and language independent. Componentization makes pattern application in the implementation phase much easier, but also fixates the behaviour to the functionality available. A componentized pattern is only applied once, and then reused, possibly in a specialised fashion; it becomes a mere recipe instead of a full—fledged description. Partial componentization does not express the full knowledge expressed in the pattern descriptions, thereby limiting the pattern applicability unless the component itself expresses pattern—like qualities such as Openness and Generativity. The same is true for any Invisible or Formal implementation.

Meyer and Arnout recognise that the language used clearly affect the componentization process [Arnout06; Meyer06, p.3,11], and that componentization affects pattern applicability [Meyer06, p.11]. Eiffel is not a dynamic language as it employs static and strong typing, but many of its special features are used, such as multiple inheritance, generics with or without bounds, contracts, agents, and cloning facilities [Arnout06, t.1]. Meyer and Arnout compare the Eiffel features used with features in Java (1.4), and question if the ideas used in the Eiffel implementations can be used in Java, although they suggest that reflection might provide some solutions [Arnout06]. Language impact and componentization are therefore closely related, which is also demonstrated by the fact that AspectJ features augment the entire componentization process in the study by Hannemann et al. As of Java 5, generics have been added to Java, but multiple inheritance and agents are not supported. However, we fail to see how the lack of these features should prevent componentization of the "Gang of Four" patterns in Java, but agree that different solutions must be implemented.

4.4.  Comparison
This section offers a quick comparison between the features utilises in the examined studies and the features found in Java 6. It also summarises common pattern behaviour identified in the individual studies as well as can be expected bearing the different scope of the studies in mind. The features listed in this section is not the final list of Java 6 features and mechanisms used in the evaluation, but provide clues to which features may be useful.

The studies on Common Lisp, Dylan, and Scheme all focus on making the "Gang of Four" implementations simpler using explicit language features found in the respective languages. The AspectJ and Eiffel implementations focus on traditional OO values, primarily reusability, where the language features used are simply the means to an end. This evaluation is somewhere in between: we do not strive to make the implementations simpler - since that depends on the eye of the beholder - but to illustrate how features in Java 6 can be utilised in the implementation process, which may spawn reusable components.

4.4.1.  Features
Sullivan concludes that dynamic features such as reflection, multiple—dispatch, higher—order functions, and predicate types have a positive impact on nearly all of the "Gang of Four" patterns [Sullivan02a, p.43]. Norvig agrees, and claims dynamic features found in dynamic languages is exactly what makes the pattern application simpler [Norvig96, p.10]. Java 6 in part supports two of these three dynamic traits described in section 4.2, i.e. dynamic typing, runtime code modification, and interpretation. Java employs static typing in favour of dynamic typing. Baring instrumentation (see the java.lang.instrumentation package), runtime code modification is not directly supported by Java. The reflection mechanism does not allow for structural changes to classes or objects, only behavioural ("read—only"). Java objects can access Meta data reflectively, such as classes and methods, and dynamic proxies can be used to create new types at runtime. Java is compiled into byte—code that is interpreted at runtime.

The studies by Norvig and Sullivan suggest that Java's reflective capabilities will be useful in the pattern implementation. Of the features listed in table 4.2 and 4.3, Java 6 supports several of them but to a varying degree. First—class types and functions are only partly supported. There is no way to create a regular class or method on—the—fly, but dynamic proxies can create duck types at runtime (see section Besides creational restrictions, types and methods can be manipulated like any other object ("second—class objects"). Modules correspond to packages. Multi—methods are not supported, but generic methods can be used in a type safe manner for any applicable type. Closures are partly supported in form of inner classes. Instantiation protocols and method combination must be explicit enforced by the developer, which is unfortunate, as these features are found useful in Common Lisp, Scheme, and AspectJ.

Meyer and Arnout list the features used for the "Gang of Four" patterns they succeeded to componentize [Arnout06, t.1]. The features used include "design—by—contract" (invariants), inheritance, multiple inheritance, generics, bounded generics, agents, and cloning facilities. Java 6 has direct support for inheritance, generics, bounded generics, and cloning. Agents, or delegates, are not directly supported by Java 6, but can be emulated by closures or using reflection. Design—by—contract and multiple inheritance are not supported. Java assertions are useless as they must be turned on to work. It may be possible to use dynamic proxies to emulate multiple inheritance.

The Hannemann et al. study does not offer much concerning which Java features to use. The comparison between features in C++ and Java 6 is already indirectly made in table 2.2.

4.4.2.  Patterns
It is interesting that Hannemann et al., Meyer, and Arnout cannot componentize at least the same set of patterns, namely Adapter, Bridge, Decorator, Facade, Interpreter, and Template Method [Arnout06; Hannemann02, t.1]. As illustrated in table 4.3, Sullivan has trouble providing simpler implementations for all of these patterns except Adapter and Decorator. Norvig does not discuss Adapter, Bridge, and Decorator, perhaps an indication of simpler implementations could not be made. This indicates the pattern abstractions are very context and problem specific. It is also interesting that out of the twenty—three "Gang of Four" patterns, only four have Class scope - and three of these are included in the above list, namely Adapter, Interpreter, and Template Method. Hannemann et al. cannot componentize the last pattern with Class scope either, Factory Method. The implementation level of these patterns thus corresponds to Informal. However, it does not say anything conclusive about language dependencies. It could seem reasonable to assume that the same language features are required regardless of language used, for example abstract classes in Template Method, package—like functionality in Facade, and composition in Interpreter. Nonetheless, Common Lisp and Scheme have no notion of classes, so this is clearly not the case for Template Method, for example. Other language features may also be applied. As an example, decoration and adaptation can be performed using dynamic proxies in Java 6. In our view, no definitive conclusions can be drawn in this respect. This corresponds with our initial belief from section 4.1.2 that the success of componentizing a given pattern into a language or library feature depends more on its abstraction and granularity level than the language in which it is implemented.

For Java and AspectJ, it is clear that Behavioural patterns are most easily componentized, with eight out of the twelve: Chain of Responsibility, Command, Composite, Iterator, Mediator, Memento, Observer, and Strategy. The last four are Composite and Flyweight (Structural) and Prototype and Singleton (Creational) [Hannemann02, t.1]. Many of the Behavioural patterns have a container—like structure, or operate on a container—like structure, for example Observer and Visitor, respectively. In our opinion, this makes them ideal for componentization, as the abstraction is not that complicated. Of the fifteen patterns componentized by Meyer and Arnout in Eiffel, there is an overlap with ten patterns from the AspectJ components. The only difference is Iterator and Singleton, while Meyer and Arnout also provide components for Abstract Factory, Builder, Factory Method (Creational), Proxy (Structural), and State (Behavioural) [Arnout06, t.1]. This is indeed a close match, and a strong indication that the abstractions described by Behavioural patterns are easily implemented in different languages. Common features used by Meyer and Arnout in these patterns include design—by—contract invariants, inheritance, generics, and to some extent agents. Features used by Norvig and Sullivan for Behavioural patterns primarily include first—class objects, multi—methods, method combination, closures, and reflection.

While Hannemann et al. have trouble with Creational patterns, e.g. Abstract Factory, Builder, and Factory Method, Meyer and Arnout provide componentization of these patterns as well. Sullivan and Norvig have no problems with Creational patterns either, and utilise many of the same features, for example first—class types and instantiation and method protocols. Singleton in AspectJ is also implemented using instantiation protocols.

Structural patterns seem to be the classification of patterns that generally causes most problems, regardless of the scope of the study in question. Gamma et al. state that Structural patterns rely on a small set of language features, namely single and multiple inheritance for patterns with Class scope, and object composition for Object scoped patterns [Gamma95, p.219]. This indicates that alternative solutions may be hard to implement. Meyer and Arnout only provide componentization of a single Structural pattern, namely Proxy, and Hannemann et al. of only two as mentioned above, e.g. Composite and Flyweight. Still, several Structural patterns provide very decent implementations according to Hannemann et al. in form of locality and (un—)pluggability, for example Adapter, Decorator, and Proxy [Hannemann02, t.1]. In unison, Sullivan and Norvig agree on simpler implementations for Adapter, Decorator, Facade, Flyweight, and Proxy. Again, there is an overlap of patterns, e.g. Adapter, Decorator, Flyweight, and Proxy.

The examined studies show that languages have great impact on the pattern implementations. The studies by Hannemann et al. and Meyer and Arnout also show that implementations can also express many of the desired pattern forces, such as Reusability, Interoperability, and Changeability, which are closely related to traditional OO concepts.

4.5.  Summary
Below, we list and then summarise the most important points from this chapter:

The level of implementation a given pattern can have in a programming language is classified as Invisible, Formal, or Informal. Invisible indicates a pattern is so much a part of the language that its usage is not noticed by the user. Formal indicates a pattern has an implementation in the language, but must be instantiated or called for each use. Informal indicates a pattern is part of a common shared vocabulary and referred to by name, but must be implemented from scratch for each use based on its description.

The studies related to dynamic languages examined conclude that dynamic features have a positive impact on nearly all of the "Gang of Four" patterns, for example reflection, first—class objects, method combination, multiple—dispatch, and higher—order functions. Several of the dynamic features discussed are present in Java 6, such as reflection, or can be simulated to some extent, for example via dynamic proxies.

The studies related to static languages examined conclude that it is possible to componentize several of the "Gang of Four" design patterns, but the language and pattern abstraction will determine if a given pattern can be implemented as a component. We believe the success of componentizing a given pattern into a language or library depends perhaps more on its abstraction and granularity level than the language in which it is implemented. Behavioural patterns seem more manageable compared to Structural patterns, with Creational patterns somewhere in between. This indicates support for advanced runtime features will be beneficial. Patterns having Class scope are more difficult to work with compared to patterns with Object scope. Several of the language features used in the pattern components are present in Java 6, for example generics.