A Survey of Three Approaches to the Automation of Design Patterns

Similar documents
Programming Support of Design Patterns with Compile-time Reflection

Shigeru Chiba Michiaki Tatsubori. University of Tsukuba. The Java language already has the ability for reection [2, 4]. java.lang.

An Introduction to Patterns

Towards Better Support for Pattern-Oriented Software Development

DESIGN PATTERN - INTERVIEW QUESTIONS

Design Patterns. Manuel Mastrofini. Systems Engineering and Web Services. University of Rome Tor Vergata June 2011

Martin P. Robillard and Gail C. Murphy. University of British Columbia. November, 1999

Concepts of Programming Languages

Pattern-Oriented Development with Rational Rose

Object-Oriented Design

Goals of Lecture. Lecture 27: OO Design Patterns. Pattern Resources. Design Patterns. Cover OO Design Patterns. Pattern Languages of Programming

Software Architecture (Lesson 2) Object-Oriented Paradigm (1)

CSCD01 Engineering Large Software Systems. Design Patterns. Joe Bettridge. Winter With thanks to Anya Tafliovich

Topics in Object-Oriented Design Patterns

Evolution of Collective Object Behavior in Presence of Simultaneous Client-Specific Views

Reflective Design Patterns to Implement Fault Tolerance

Object-Oriented Design

Coordination Patterns

Pattern-Based Architectural Design Process Model

RECODER - The Architecture of a Refactoring System

Chapter 13 Object Oriented Programming. Copyright 2006 The McGraw-Hill Companies, Inc.

Behavioral Design Patterns Used in Data Structures Implementation

Lecture 13: Design Patterns

Frameworks Representations & Perspectives Position Paper Workshop on Language Support for Design Patterns and Frameworks, ECOOP 97

Configuration Provider: A Pattern for Configuring Threaded Applications

Pattern Resources. Lecture 25: Design Patterns. What are Patterns? Design Patterns. Pattern Languages of Programming. The Portland Pattern Repository

Tuesday, October 4. Announcements

Motivation. ! Stop reinventing the wheel, try to reuse code! ! How do you organize code reuse? History: " Copy & Paste. " Collect useful files

INCORPORATING ADVANCED PROGRAMMING TECHNIQUES IN THE COMPUTER INFORMATION SYSTEMS CURRICULUM

Universal Communication Component on Symbian Series60 Platform

ADAPTER. Topics. Presented By: Mallampati Bhava Chaitanya

Design Patterns IV. Alexei Khorev. 1 Structural Patterns. Structural Patterns. 2 Adapter Design Patterns IV. Alexei Khorev. Structural Patterns

Jarcler: Aspect-Oriented Middleware for Distributed Software in Java

Design Patterns IV Structural Design Patterns, 1

DESIGN PATTERN MATCHING

Idioms for Building Software Frameworks in AspectJ

M301: Software Systems & their Development. Unit 4: Inheritance, Composition and Polymorphism

Object-Oriented Design

Idioms and Design Patterns. Martin Skogevall IDE, Mälardalen University

Object-Oriented Concepts and Design Principles

Short Notes of CS201

CS201 - Introduction to Programming Glossary By

A System of Patterns for Web Navigation

Software Design Patterns. Background 1. Background 2. Jonathan I. Maletic, Ph.D.

EPL 603 TOPICS IN SOFTWARE ENGINEERING. Lab 6: Design Patterns

Tool Support for Refactoring Duplicated OO Code

A Type Graph Model for Java Programs

A Meta-Model for Composition Techniques in Object-Oriented Software Development

Programming Languages 2nd edition Tucker and Noonan"

Design Patterns Design patterns advantages:

Patterns for polymorphic operations

Introduction to Design Patterns

L23.1 Introduction... 2

Design Pattern. CMPSC 487 Lecture 10 Topics: Design Patterns: Elements of Reusable Object-Oriented Software (Gamma, et al.)

Produced by. Design Patterns. MSc in Communications Software. Eamonn de Leastar

Inheritance (Chapter 7)

A Metric for Measuring the Abstraction Level of Design Patterns

A Primer on Design Patterns

Facade and Adapter. Comp-303 : Programming Techniques Lecture 19. Alexandre Denault Computer Science McGill University Winter 2004

Cover Page. The handle holds various files of this Leiden University dissertation

Slide 1. Design Patterns. Prof. Mirco Tribastone, Ph.D

A Metric of the Relative Abstraction Level of Software Patterns

Implementing Object Equivalence in Java Using the Template Method Design Pattern

Lectures 24 and 25 Introduction to Architectural Styles and Design Patterns

Towards a Java Framework for Knowledge Representation and Inference

On the correctness of template metaprograms

NOTES ON OBJECT-ORIENTED MODELING AND DESIGN

Introduction to Design Patterns

Reflective Java and A Reflective Component-Based Transaction Architecture

Object Oriented Methods with UML. Introduction to Design Patterns- Lecture 8

DAT159 Refactoring (Introduction)

Exam in TDDB84: Design Patterns,

Introduction to Design Patterns

Dynamic Instantiation-Checking Components

Control Message. Abstract. Microthread pattern?, Protocol pattern?, Rendezvous pattern? [maybe not applicable yet?]

AOSA - Betriebssystemkomponenten und der Aspektmoderatoransatz

CISC 322 Software Architecture

What are the characteristics of Object Oriented programming language?

Chapter 6 Introduction to Defining Classes

Today s lecture. CS 314 fall 01 C++ 1, page 1

Chapter 7. Modular Refactoring. 7.1 Introduction to Modular Refactoring

Coordinator. Example. Prashant Jain Corporate Technology, Siemens AG Munich, Germany

Specification and Automated Detection of Code Smells using OCL

junit RV Adding Runtime Verification to junit

Implementing Software Connectors through First-Class Methods

Software Engineering

COFFEESTRAINER - Statically Checking Structural Constraints on Java Programs

SUMMARY: MODEL DRIVEN SECURITY

Dr. Tom Hicks. Computer Science Department Trinity University

Software Engineering Prof. Rushikesh K.Joshi IIT Bombay Lecture-15 Design Patterns

Contents. Chapter 1 Overview of the JavaScript C Engine...1. Chapter 2 JavaScript API Reference...23

CSCD01 Engineering Large Software Systems. Design Patterns. Joe Bettridge. Winter With thanks to Anya Tafliovich

Design Patterns: Part 2

CPSC 427: Object-Oriented Programming

Object Oriented Paradigm

Chapter 1: Object-Oriented Programming Using C++

be used for more than one use case (for instance, for use cases Create User and Delete User, one can have one UserController, instead of two separate

Design Patterns. "Gang of Four"* Design Patterns. "Gang of Four" Design Patterns. Design Pattern. CS 247: Software Engineering Principles

The Contract Pattern. Design by contract

Capturing JUnit Behavior into Static Programs

Transcription:

A Survey of Three Approaches to the Automation of Design Patterns Paul Pop paupo@ida.liu.se Computer and Information Science Dept. Linköpings universitet Abstract Design patterns are a popular object-oriented technique used to describe common design problems, their context and their solutions. Although design patterns have proved very successful at organizing and building large systems, there are still problems associated with them. One of the main problems is that their informal, textual description is not suitable for tool support, and thus patterns have to be applied manually, which is time consuming and error prone. This paper surveys three approaches to the automation of design patterns that aim at simplifying the application of patterns through tool support. The methods are evaluated based on a set of requirements that measure how useful each approach is in supporting the application of patterns for large object-oriented systems. 1. Introduction Previous papers in this collection have provided a solid introduction to the object-oriented software development field in general, and to design patterns in particular. Several definitions have been proposed for design patterns (TODO: add here references to other papers in this compendium). Loosely speaking, a design pattern is a solution to a problem in a context. Patterns are expressed textually, in an informal manner, their description consisting of a name, a problem and its associated context, a discussion and a solution. The message so far has been that design patterns are a very promising approach of building and organizing large systems. Over the years, however, several weaknesses of design patterns have been identified. Some of the problems, together with the proposed solutions, are described in the papers of this compendium (TODO: add here references to other papers in this compendium, maybe detail the problems). A major problem, on which we will concentrate in this paper, is the lack of a systematic way to apply design patterns. The problem derives from the informal, textual description of design patterns, which is not suitable for tool support, and thus patterns have to be applied manually, which is time consuming and error prone (the lack of automation problem). According to (Schultz et al., 1998), there are two ways in which design patterns can be viewed: either as building blocks, as in (Buschmann, 1996), or as operators. The difference is that when viewed as building blocks, the design patterns focus on describing the target structure, which results after design patterns are applied. This is useful when new systems are constructed, but it makes difficult the process of modifying existing systems. On the other hand, if design patterns are viewed as operators, then they are described as a series of steps, which have to be performed in order to modify the existing system according to the design pattern. Today, designers very seldom start from scratch when building new systems; more likely is that legacy systems and components have to be reused. In this paper we survey three approaches to the automation of design patterns that aim at simplifying the application of patterns through tool support. In the first approach Schultz et al. consider design patterns to be operators that are applied to transform an existing design into a target design. The application of the design patterns is divided into five steps: identification of the problem structure, checking of pre-conditions, parameterized transformation of the problem structure into the target structure, reorganization of context and check of post-conditions. The second approach (Tatsubori et al., 2000) provides language constructs similar to macros, which are used by the programmer to streamline the application of design patterns. The last two approaches, COMPOST (Assmann et al., DATE?) and Recoder (Ludwig et al., DATE?), are discussed together. COMPOST 1

views the application of design patterns as a software composition problem, where the exiting system is modified into a target system, according to the design pattern, using an invasive composition technique. Recoder, based on COMPOST, uses a refactoring approach to the systematic modification of software systems aimed at automatically introducing design patterns into an existing design. The refactorings are supported by detailed information about the source code, contained in a special database called the program metamodel. The methods presented are evaluated based on a set of requirements that measure how useful each approach is in supporting the application of patterns for large object-oriented systems. We use the requirements from Schultz et al. which have identified the following proprieties that must be fulfilled by a reorganization methodology in order to be practically applicable for large object-oriented software systems: Language independence: The methodology should not rely on a specific object-oriented programming language. Level of abstraction: The methodology should aim at the design level rather than the implementation level, since most of the problems of an object-oriented system which can be solved by reorganization (e.g., lack of flexibility) concern the design of that system. Behavior preservation: The goal of reorganization is not to change the functionality of a given system, but to improve the structure of that system in order to make functionality changes easier. Therefore, a reorganization operation should not change the system's behavior. The methodology must be proven to preserve behavior. Tool support: The methodology should allow for tool support, since reorganizing a large system by hand is error-prone and time-consuming. The paper is organized in 5 sections. The next two sections detail the problems associated with the application of design patterns using an example: section 2 introduces the adapter pattern, and in section 3 we show how is the adapter pattern applied manually to adapt a class Vector to an interface Stack. Section 4 starts with the aim of a design pattern automation methodology and presents existing (i.e., Together) tool support for the automation of design patterns. Then, the three approaches to the automation of design patterns are outlined, and the adapter pattern is used to exemplify the application of the methods. (TODO: Remove the next sentence if you don t want section 5) Section 5 tries to extrapolate from the existing tool support for design patterns proposing a method of pattern automation that extends beyond software engineering. The last section presents a discussion and our conclusions. 2. Pattern Example: The Adapter Pattern Figure 1. The Adapter Pattern InStack.java this section, the problems related to the applicationveofcto design r.javapatterns and the proposed solutions, are public discussed using an example of a design pattern. The example has be simple enough to facilitate VectorStack.java interface public class VectorStack public implements class Vector Stack the { discussion, and complex enough to be useful in underlining the problems. { { boolean private isempty(); Vector v; boolean isempty(); Enumeration VectorStack(Vector elements(); v) { this.v = v; Enumeration elements(); Object boolean peek(); isempty() { return v.isempty(); Object lastelement() {...; void push(object Enumeration o); elements() { return v.elements(); void a ddele me nt(obje ct o) {..; Object Object pop(); peek() { return v.lastelement();... 2 void push(object o) { return v.addelement( o ); Object pop() {...

Figure 3. The VectorStack class which implements the adapter pattern Thus, we have decided to use the adapter pattern (figure 1). The adapter pattern is used to convert the interface of a class into another interface the clients expect. The adapter lets classes work together that couldn t otherwise because of incompatible interfaces (Gamma et al., 94). Figure 1 shows a structure of the adapter pattern. Let us suppose that a programmer has to adapt a class Vector to an interface Stack, which are defined as in figure 2. 3. Manual Implementation of Design Patterns The adapter pattern in figure 1 adapts an adaptee class to a target interface. In our case, the class Vector and an interface Stack correspond to the adaptee and the target, respectively. In order to implement the design pattern, a class called VectorStack which corresponds to the adapter -- has to be written. The purpose of the VectorStack class is to extend the class Vector to have the interface Stack. This has to be done such that the VectorStack class is not a subclass of the class Vector, otherwise a single adapter cannot work with several adaptees. To do this, programmers have to manually write the class VectorStack which plays the role of the Adapter, they are faced with some problems, identified in (Tatsubori et al., 2000): 1. Although the class VectorStack is written for the Adapter of the Adapter pattern, it is difficult to find out this fact from the source code. Which design pattern is used? What is the role of the class VectorStack? 2. The programmers must add a field that holds a reference to a Vector object and a constructor to accept it. Although isempty() and elements() are shared between the class Vector and the class VectorStack programmers must repeatedly write code for both of them. 3. In the body of the method peek(), only the method lastelement() is invoked on the Vector object and the value obtained by this invocation is returned intactly. Such a trivial operation of object also appears in the method push(). Describing those operations is a boring task and error prone. These problems are common to most of the design patterns, and they are well documented in the research literature (Bosch et al., 1996). Bosch calls the problems 1, 2 and 3, traceability loss, self problem, and implementation overhead, respectively. 4. Approaches to the Automation of Design Patterns It becomes clear now that tool support is needed in order to address the problems a designer faces when implementing design patterns manually. Such a tools should solve or address the problems of design patterns mentioned in the previous section: traceability loss, self problem, and implementation overhead. Moreover, such a tool, that provides support for the automation of design patterns, should fulfill as much as possible of the requirements of an reorganization methodology set out in the introduction: language independence, high level of abstraction, behavior preservation. There are a number of tools on the market, aimed at providing tool support for design patterns, in one form or another. The tools range from simple static analysis of Java programs, like the Barat or Recoder tools, more complex refactoring tools like the XPTools, to full blown integrated development environments, that offer extensive automation support for design patterns, like the Together environment, from TogetherSoft. There are basically three abstraction levels at which a user can interact with these tools: the pattern level, the design level, and the code level. At the pattern level the tools help designers introduce patterns into existing systems, link patterns together, replace or remove patterns. One abstraction level lower, at the design level, the designer sees the system as a set of classes, with their methods and relationships like association, inheritance etc, while at the code level all the operations are done by manipulating the static source code of programs. For more examples the reader is directed to (Florijn, 1997), which provides a list of tools for the automation of design patterns, as well as good starting points for further exploration. One of the more mature tools that offer support for design patterns is the Together tool from TogetherSoft (Together, 2001), presented in figure 4. Basically, Together is an IDE which supports several programming languages like Java as well as C++, C#, and Visual Basic, and provides support for common software engineering tasks. In figure 4 the user is presented with the design level and the 3

source code level of a Java project opened in Together 5.5. As can be seen from figure 4, the designer has implemented an interface Stack and a Vector class. Let us see how Together supports the automatic introduction of the adapter pattern, used to adapt the Vector class to the Stack interface. Using Together, the designer can select the Object -> Choose Pattern command, which brings up a dialog box, presented in figure 5, that allows the selection of a design pattern to be applied. Among the patterns presented to the left of the dialog, the designer will choose the Adapter pattern filed in the GoF patterns folder, which contains the patterns from the Gang of Four book [xx]. The pattern is described in a text area to the bottom of the dialog. To the right, there is a list of properties that have to be set before the adapter pattern can be applied. First, the adaptee and target classes have to be identified. This is done by pointing in the design, at the classes that will fulfill this role. Other properties, like Copy documentation or Create pattern links can also be set. Once all the properties are set to the desired valued, the designer presses Finish which leads to the automatic application of the adapter pattern, that modifies the system presented in figure 4 to the system in figure 6. The application of the design pattern has created a new class, called Adapter, depicted in figure 6. This class is the equivalent of the VectorStack class written manually by the designer in section 3. The class implements a Stack interface, and the cosntructor isempty(), and elements() methods have been created automatically, thus reducing the manual implementation overhead. Figure 6 also shows the relationships between the Stack interface, Vector class and the newly created Adapter class. Together has to approaches to the automation of design patterns: pattern templates and the pattern API (application programming interface). The first approach expresses the pattern as a name-replacement template, using a simple ASCII file. The disadvantages of this approach are that no instance-specific customization is possible, and there is no completeness or consistency checking applied. These disadvantages are addressed by the second approach, the pattern API, which expresses the pattern in Java using a special API provided by TogetherSoft. 4

We will now present the pattern API approach to pattern automation used in the Together tool. The Figure 6. Pattern Automation using Together fist thing to be determined, before using the API provided to write the pattern, is to decide the level if language dependence. The pattern can be written for only a single language, like Java or C++, or it can be a generic pattern, which can be used with any language. Then, the type of pattern has to be decided, and based on this decision different classes in the pattern API will be used to derive the new pattern. The pattern type can be either a class, a link, or a member. After the pattern has been written using the provided API, the.class files resulted from the compilation of the Java code have to be placed in a special directory structure that holds all the patterns which can be applied to transform the system. The Together user inferace then interogates the patterns, which respond apropriately if they adhere to the TogetherSoft s standard pattern API. This interaction is done through the SciPattern interface, which has the following properties and members: SciPatternProperty.PATTERN_CATEGORY property Indicates the kind of object this pattern is applicable to. prepare() Checks if it is possible at all to apply this pattern to the target objects and makes some start-up preparations for the pattern. canapply() Checks whether the pattern can be applied to the target objects with the current values of pattern's properties. apply() Makes the pattern perform desired actions. PropertyMap properties set Defines the behavior of a pattern. 5

This method fulfils all the requirements for a reorganization methodology, put forward in the introduction. However, programmers have to be careful when using the pattern API not to change the behavior of the system. Next sections will present four research approaches to the automation of design patterns, which are later evaluated based on the four criteria: language independence, high level of abstraction, behavior preservation, and tool support. 4.2 Schultz et al. (Schultz et al., 1998) consider design patterns to be operators that transform an existing design into a target design. They provide a systematic approach in which the process of applying design patterns is divided into five steps (adapted from Schultz et al., 1998): 1. Identification of the problem structure: The software engineer identifies the part of the existing design that should be reorganized. In our example, the application of operator Bridge aims at decoupling the abstraction (super-class Set) from its implementations. The problem structure comprises the class Set and its descendants. 2. Check of pre-conditions: All pre-conditions must hold in order to apply the design pattern operator. In our example, the implementations HashSet and ListSet must provide the same interface as the abstraction Set in order to be interchangeable. 3. Parameterized transformation of the problem structure into the target structure: In this step the design pattern application itself is put into place. The process is divided into generic aspects (depending on the design pattern) and application specific aspects (parameters). The user parameterizes the process by choosing an appropriate variant of the design pattern. Additional parameters are for example the set of methods which will be delegated or the decision whether the class of the implementation object shall be interchangeable at run-time or not. 4. Reorganization of context: The transformation of the problem structure often causes a change to its interface. The clients of this interface affected by the change have to be reorganized in order to provide the same functionality as before. 5. Check of post-conditions: Post-conditions must hold after the design pattern has been applied. It is often hard to formalize post-conditions as they usually depend on semantics. Therefore they are often described informally. The transformations applied to change the design are described in terms of operations on a meta model that contains classes, methods, parameters and attributes, and are captured using a language with three types of constructs: transformation operations, e.g., applydelegation( < from >, < to >, < Params > ) parameterizations by the user, e.g., < InputVar >?: < VarType > [ < InitList > ] miscellaneous operations, e.g., conditions and labels Thus, the automation process becomes an algorithm described with the formalisms outlined above. Such a transformational approach enables the use of design patterns as reorganization operators in order to reorganize existing systems by identifying the problem structure and transforming it into an improved target structure. (Schultz et al., 1998) mention that while design pattern operators fulfill the first two requirements, (i.e., they are language independent and deal with design aspects) they fail to fulfill the last one (tool support). Not only is the underlying model too abstract to be implemented in a tool, but the pattern operators also lack proof of behavior preservation. To address this problem, (Zimmer, 1997) propose a formalization of the operators, as well as their pre-conditions and post-conditions with the aid of refactorings. This means, replacing the meta-model and the operator-language defined in (Zimmer, 1997) with the model and language defined in (Opdyke, 1992). In (Opdyke, 1992) an approach for the support of the evolution of object-oriented systems is presented. This is achieved through refactorings which are implementable as a tool and showed that the application of these refactorings does not change the system behavior, refactorings being low level operators that preserve the semantics. In (Opdyke, 1992) 26 low-level refactorings (like create empty class, add function argument, etc.) and 3 high-level refactorings (converting an inheritance relation into an aggregation, etc.) are presented. We can now show how this combination of methods from (Schultz et al., 1998) and (Opdyke, 1992) we can be applied in practice. Thus, figure 6 depicts the third step of the application of the design 6

pattern operator Bridge as performed by the new approach. The intent of a bridge pattern is to decouple an abstraction from its implementation so that the two can vary independently. The sequence of necessary transformation steps is different from the sequence in (Zimmer, 1997), since the new approach requires behavior preservation at every step. In step 3a a new, unreferenced class AbstractSet is introduced. AbstractSet is assigned to the same super-class (not shown in the figure) as Set in step 3b. Figure 6. Pattern Automation using Together The introduction of a component relationship between Set and AbtractSet, the copying of the interface of Set to AbstractSet and the delegation of all methods of AbstractSet to its component Set is depicted in step 3c. Step 3d contains the most crucial refactoring. First the constructor method of AbstractSet is changed to include one parameter determining the actual implementation (e.g., HashSet or ListSet) of the set. Then every construction of a set (subclass of Set) is changed to use the new constructor of AbstractSet and every variable definition using Set or one of its subclasses as a type is changed to AbstractSet. Finally in step 3e a new method changeimpl can be introduced in the class Set to determine the actual implementation class of the set. 4.3 Open Java Another approach to the automation of design patterns is through the use of reflection, advocated by (Tatsubori et al., 2000). Reflection is a software engineering technique for changing the behaviour of a program according to another program. Reflection can be used for weaving several components, or aspects, like algorithms, distribution, resource allocation, user interfaces, etc., into a single executable program. Reflection is present in a simple form in macro systems, which are systems that manipulate programs at compile time. Macro systems perform textual substitution such that a particular aspect of a program is separated from the rest of a program. In the example below, 7

#define MAX 100 int array[max]; the C/C++ macro system has been used to separate the definition of a constant value from the rest of the program. The C/C++ macro system is based on the #define constructs which perform a simple token based substitution. VectorStack.oj public class VectorStack instantiates AdapterPattern adapts Ve ctor to S tack { Object peek() forwards la s tele ment; void push(object o) forwards addelement; Object pop() {... Figure 8. The OpenJava Language Constructs There are, however, more complex macro systems. For example Common Lisp macros are programable macros which receive an abstract syntax tree (AST) and substitutes it for the original expression. Such an approach is powerful: the object system of Common Lisp is actually implemented with this macro system. The common feature of such macro systems is that they use ASTs for representing a source program. However, several drawbacks related to macro systems have been reported which make their use for design pattern automation very difficult if not impossible. (Tatsubori et al., 2000) mentions several drawbacks related to the AST representation for macros, the main problem being that ASTs are a purely textual representation of the program. This means that no type information is captured by the ASTs, type information which is crucial for enabling automated support for complex design patterns. (TODO: It would be nice to have an example for the previous idea) Thus, (Open Java) proposes a macro system, called OpenJava, which is a compile time reflective system for both behavioural and structural reflection. The main advantage from the more traditional macro systems presented before is that the OpenJava macros use class metaobjects for representing the logical entities of a program instead of simple token sequencies or ASTs. Class metaobjects are a sofisticated source code representation that capture the logical structure of a calss definition and manage the expansion of the related class. All class metaobjects are derived from the OJClass, which provide methods that have to be customized in order to describe the exact macro expansion mechanism, see figure 9. Let us now see how the OpenJava approach can be used for the adapter pattern example introduced in section 2. Thus, from the viewpoint of the Adapter pattern, programmers have only to define which method of the class Vector corresponds to each methods of the interface Stack. This is because the Adapter only maps methods of the Target to methods of the Adaptee. In an extended language supporting the Adapter pattern, programmers should be able to directly handle such forwardings. According (OpenJava) an implementation in that extended language should enable programmers to: 1. declare that the program uses the Adapter pattern; 2. declare an Adapter class, a Target class, and an Adaptee class; 3. specify mapping between methods of the Adapter class and methods of the Adaptee class. OpenJava uses the following constructs to fulfill the three points above: 1. A declaration instantiates P specififies that a design pattern P is used. 2. A declaration adapts A to T specifies that this class is an Adapter adapting the class A to the interface T. 3. A declaration at the end of a method signature forwards M specifies that the method forwards to the method M of the Adaptee. An Adapter class has methods corresponding to all the methods of the Adaptee class. Even if they are not explicitly defined, they are automatically inserted in the Adapter class. They forward to the 8

Adaptee s method with the same name and signature. These lanugage constructs simplify programs written according to the Adapter pattern. In OpenJava,the language extension shown above is implemented by a metaclass AdapterPattern, derived from OJClass. Once this metaclass is written, other programmers can benffit from the metaclass and thereby write programs involving extended language constructs. The source code of this metaclass given is figure 9. AdapterPatte rn.o j public class AdapterPattern extends OJClass { void init() { /* overrides for syntax extensions */ registerdeclarationsuffix( "adapts",.. ); registermethodsuffix( "forwards",.. ); /* overrides for translation */ void translate() throws MOPException { ParseTree sfx = this.getsuffix( "adapts" ); OJClass adaptee = OJClass.forName(..sfx.. ); OJClass target = OJClass.forName(..sfx.. );... /* adds a field to hold an Adaptee */ this.addfield(.."adaptee".. ); /* adds a constructor to accept an Adaptee */ this.addconstructor(.. ); /* adds an interface as a Target */ this.addinterface( target ); Figure 9. Adapter Pattern Implemented Using OpenJava s API According to this metaclass, the OpenJava system produces regular Java source code equivalent to the code in figure 3 from the code in figure2. 4.4 COMPOST and Recoder In section 4.2 we have discussed the approach from (Schultz et al., 1998) which provides a systematic way of applying design patterns, based at its lowest level on refactorings. Another approach, besides refactoring, is to view the application of design patterns as software composition. Software composition aims at better reuse through information hiding, and standardized interfaces. One common aspect of software composition approaches was that they treated components as black boxes. However, recent approaches to software composition have opened up components, so that they can be merged during the composition, the result being an invasive software composition, see figure 10. The COMPOST system (Assmann, DATE?) combines the benefits of refactoring and componentbased engineering, offering a component based model that guarantees information hiding and type checking, and a set of transformations which can be applied to component interfaces for a more flexible composition. The application of design patterns can be viewed in this context as an invasive composition through which the existing classes are modified to cooperate with the design pattern (the component) introduced into the system. Such an approach, while elegant, might not be very intuitive for the designer which operates using design patterns. For a better support of incremental software development a new framework, called Recoder, has been built based on COMPOST. Recoder is a framework for static (source code) meta programming of Java program sources, which offers the following features: parsing and unparsing of Java sources, 9

name and type analysis for Java programs, transformation of Java sources, incremental analysis and transformation of Java sources. Thus, parsing and unparsing of Java sources could be used for constructing simple preprocessors, simple code generators, or source code beautification tools. Name and type analysis could be the basis for software visualization tools, software metrics, and design problem detection tools, while the transformation of Java sources could lead to preprocessors, semantic macros, aspect weavers, compilers, etc. The incremental analysis and transformation feature is the one that is the most suitable for design patterns, but also source code optimization, refactoring tools, etc. Compos er Invasively transformed code Figure 10. Invasive Composition using the COMPOST System The core of Recoder is a database that contains a model of the program, called program meta model, see figure 11a. The model contains semantic entities and relations as defined by the Java programming language, and well as other derived data inferenced from the language specification and source program. To be able to implement patterns, a designer has to write coresponding metaprograms using the Recoder API, see figure 11b. Such metaprograms query the model and the inferencer services. They change only the abstract syntax of the model, and have to report their changes to a change history object, which makes rollback possible. TypeDeclarationMutableList list = u.getdeclarations(); if (lis t == null) { list = new TypeDeclarationArrayList(); u.setdeclarations(list); lis t.add(d); a) b) Figure 11. a) Recoder s Program Model Database b) Using Recoder API 10

5. Conclusions While design patterns are a popular object-oriented technique used to describe common design problems, their context and their solutions, we have shown that one of the main problems is that their informal, textual description is not suitable for tool support. Thus, patterns have to be applied manually, which is time consuming and error prone. This paper has presented three approaches to the automation of design patterns: Schults et al, OpenJava and COMPOST/Recoder. In the first approach Zimmer et al. considers design patterns to be operators that are applied to transform an existing design into a target design, and provides a systematic technique, based at its lowest level on refactorings. The second approach (Open Java) provides language constructs similar to macros, which are used by the programmer to streamline the application of design patterns. Lastly, COMPOST views the application of design patterns as a software composition problem, and serves as a basis for Recoder, which provides a more complex API for other types of refactorings. The approaches to the automation of design patterns aim at simplifying the application of patterns through tool support. The methods were evaluated based on a set of requirements that measure how useful each approach is in supporting the application of patterns for large object-oriented systems. References E. Gamma, R. Helm, R. Johnson, and J Vlissides. Design Patterns: Elements of Reusable Object- Oriented Software. Addison-Wesley, 1995. F. Busschmann, R. Meunier, H. Rohnert, P. Sommerland, M. Stal. Patter-Oriented Software Architecture A System of Patterns. 1996. B. Schulz, T. Genssler, B. Mohr, and W. Zimmer. Design pattern as reorganisation operators. Technical report, FZI, 1998a. Together, http://www.togethersoft.com B. Schulz, T. Genssler, B. Mohr, W. Zimmer. On the Computer Aided Introduction of Design Patterns into Object-Oriented Systems. Proceedings of Technology of Object-Oriented Languages, 258 267, 1998b. Frameworks und Entwurfsmuster W. Zimmer, PhD thesis, FZI, 1997 U. Assmann, T. Genssler, D. Heuzeroth, A. Ludwig, R. Neumann. Refactoring and Beyond, (TODO: add publication place and date) COMPOST s web page: http://i44w3.info.uni-karlsruhe.de/~compost/ W. Opdyke. Refactoring Object-Oriented Frameworks. PhD thesis, University of Illinois at Urbana- Champaign, 1992. Michiaki Tatsubori, Shigeru Chiba, Marc-Olivier Killijian and Kozo Itano. OpenJava: A Class-Based Macro System for Java. Lecture Notes in Computer Science 1826, Reflection and Software Engineering,, Walter Cazzola, Robert J. Stroud, Francesco Tisato (Eds.), Springer-Verlag, pp.117-133, 2000. OpenJava s web page: http://www.softlab.is.tsukuba.ac.jp/~mich/openjava/index.html 11

A. Ludwig, D. Heuzeroth. Recoder. http://recoder.surceforge.net J. Bosch. Language Support for Design Patterns. TOOLS Europe 96, 1996. G. Florijn, M. Meijers, P. Winsen. Tool support in design patterns. Proceedings of the European Conference on Object-Oriented Programming June 1997. M. OCinneide and P. Nixon. A methodology for the automated introduction of design patterns. Hongji Yang and Lee White, editors, Proceedings of the International Conference on Software Maintenance pages 463 472, 1999. Tool support for object-oriented design patterns http://www.serc.nl/people/florijn/work/patterns.html W. Zimmer. Relationships between design patterns. In J. Coplien and D.C. Schmidt, editors, Pattern Languages of Program Design. Addison-Wesley, 1995. 12