Automating the Application of Design Patterns. Amnon H. Eden1. Joseph (Yossi) Gil 2. Amiram Yehudai1. Abstract. Design patterns today form a principal ...
Automating the Application of Design Patterns Amnon H. Eden1 Joseph (Yossi) Gil 2 Amiram Yehudai1
Abstract Design patterns today form a principal heuristic of OOD and are widely used in numerous application domains. However, lack of suitable formalisms prevents the automation of the technical aspects in their implementation. We present an approach of rigorous specification of design patterns and a prototype of a tool that automates most of their application. This tool is also capable of enforcing design principles that can be expressed in terms of constructs and relations in an OOPL. Design patterns are a fundamental object oriented design heuristic. Today, they form the most important means of delivering knowledge and experience from the expert to the novice, from the veteran to the recruit. A description of the design patterns of a well-designed class library is the most efficient method of abstracting its description and delivering its essentials, leaving out the numerous dispensable detail that may not contribute to the design of future libraries. For these reasons a great deal of research is conducted in the attempt to discover and describe design patterns. The readers that are not familiar with design patterns can use [Gamma et. al 95] and [Coplien 94] as introductions to the topic. There are three types of activities in the research of design patterns: 1. The “discovery” or invention of new patterns 2. The classification and description of design patterns 3. and application of design patterns This distinction reassures the observation of the practice of design patterns is both science and art. It is art in the sense that scientific discovery is art, much in accordance to the oldfashioned philosophical concept of “context of discovery”. As a result, the detection or “invention” of design patterns are activities that cannot be reduced to a small set of logical deductions by today’s means. For the same reason their “automation”, if possible at all, requires techniques that appear to belong to the realm of artificial intelligence (AI) or knowledge-based reasoning. Nonetheless, the more “scientific” aspects of this practice numbered 2 and 3 in our list appear to be good candidates for automation, or so we claim. The manual application of many simple patterns (such as the Prototype and Observer design patterns described in [Gamma et. 1
The Department of Computer Science, School of Mathematics, Tel Aviv University, Tel Aviv, Israel.
2
The Faculty of Computer Science, The Israeli Technion, Haifa, Israel.
This material is presented to ensure timely dissemination of scholarly and technical work. Copyright and all rights therein are retained by authors or by other copyright holders. All persons copying this information are expected to adhere to the terms and constraints invoked by each author’s copyright. In most cases, these works may not be reposted without the explicit permission of the copyright holder.
al 95]) is often time consuming and technical, hence an error-prone activity. The programmer that implements one of these patterns using some OOPL is required to repeatedly apply selected programming idioms of low abstraction levels even in the case of sophisticated OOPLs. If only there was a way to “ mechanize” the application of these patterns or automatically validate their application in a particular context, it would have made a significant contribution to the abstraction level of the programmers work. It seems that the solution to the problems that are related to the application of patterns was within reach if only there was a way to formalize the operations and the actors that participate in the pattern implementation. At present, without suitable formalism, design patterns are described partly using class diagrams, each depicts a certain application of this pattern, partly using object diagrams, each depicts a particular instance of this pattern, and partly using source code text that illustrates a particular implementation. Since none of these tools is Add the routine clone to class C: Set the routine’s return value to: C * Set the routine’s arguments to: List cloned_list of pairs of objects and their clones (both of type void *) Set the routine’s name to be: “clone” Set the routine’s body to be the following: if (cloned_list) contains this object then return its clone, else continue. Create a new object result of class C on the free-store Add the pair to cloned_list For each data member m of result do: result.m := duplicate(this.m) where the interpretation of the function duplicate depends on the type of its argument: If m is of a pointer to a fundamental type and m z nil then return a newly allocated copy of m else if m is of a pointer to a class and m z nil then recursively call m.clone(cloned_list) else if m is held by value then use the assignment operator for copying m Return result Add another (overloaded) version of clone to class C: Set this routine’s signature to be the same as the other’s, only this one has no arguments. Set the routine’s body to have the following statements: Create a local list object l Return the result of calling clone(l) Table 1: An algorithm that implements a variation of the prototype pattern [Gamma et. al 95] in C++. To simplify this example it was assumed that there are no reference members. With pointer members it is assumed they hold either 0 or the address of a single valid object allocated on the free store.
-2-
complete with reference to design patterns, they are mainly described by natural language prose. Using natural language prose as the principle means of patterns’ specification may seem natural to the followers of Alexander [77], which founded the patterns’ revolution. Nevertheless, whatever benefit vagueness and ambiguity of the natural language bear to architecture and interior design they are not desired in the case of software engineering. Looking for example at the Prototype and Observer design patterns described in [Gamma et. al 95], although the principles that govern each pattern are very few it takes a number of pages containing class diagrams, object diagrams, code samples, and mostly English text to convey its notion to its fullest extent. In conclusion, within the domain of software engineering lack of formalism impairs the expressiveness of patterns’ specifications and prohibits the automation and validation of patterns’ application. The question is therefore how much, if any, of the specification of design patterns may be expressed rigorously? In other words, what parts of patterns' specifications are “ scientific” enough to allow their precise qualification? Even restricting ourselves to the interpretation of the term design pattern as given in [Gamma et. al 95] clearly not every formation, role, or relation that participates in the pattern’s account follow some formal rule. Yet our study shows that many design patterns are simple enough to allow recording a precise account of most of the steps that are taken towards the application of this pattern in a certain context. In fact we claim that the same “ precise account of programming steps” can serve as the key to both the formalization of design patterns and to their automation. By this approach a design pattern is specified rigorously simply by giving an algorithm to its application. The example in Table 1 depicts an algorithm that implements a particular variation of the Prototype pattern in C++. If design patterns can be specified by algorithms then it is only natural to use a programming language as the language by which the design patterns'algorithms are expressed. The term metalanguage refers to the language by which constructs of some other language are manipulated. The object language is the OOPL that is being manipulated. Because by this approach design patterns are treated as programs that manipulate other programs, it is best described as a metaprogramming. The automation of design pattern applications is therefore possible by their formulation in the metalanguage. We now may create a tool that reads class declarations in the object language, generates an abstract representation of these classes, and allows the specification and application of design patterns in the metalanguage. Note that this tool, nicknamed the patterns wizard in our work, is supposed to parse text in the object OOPL and create a data structure that represents the classes, relations, objects, statements, and every other element of the object language. One may ask what is the purpose of regenerating the object language source? Why is the representation in the object language necessary? An alternative would be to view the pattern specification language (that is a form of the metalanguage) as a replacement to the object language, i.e., a programming language that is self contained, which is also more abstract than the object language. The answer is that learning from experience with past abstraction mechanisms, such as 4GLs (4th-generation languages), initial CASE tools, code generators and application generators, it appears that when high-level constructs assumed the place of the old-fashioned programming language the result is always a language of a expressive power limited to a very specialized domain. The expressive power of existing OOPLs and other programming languages has its own merits, and higher-level tools need not replace it but enhance it. Also with design -3-
patterns we clearly cannot expect the wizard to be complete with reference to the patterns’ semantics, not even with reference to the simplest patterns. In order to allow the programmer to complement and monitor the wizard’ s operations our wizard needs to behave as an “ apprentice” to the programmer. That is, to act as one that operates in the same development environment the programmer used before, e.g., next to the editor, the compiler, etc. In a typical scenario a set of class declarations is parsed, an abstract representation is created, and a pattern routine is applied, resulting in modifications to the abstract representation. The application of this pattern is completed by regenerating the source code and manually editing it. A prototype to the patterns wizard was implemented using Smalltalk as the metalanguage and Eiffel as the object language. As initial test cases we implemented the Observer design pattern [Gamma et. al 95], and detected violations of the Law of Demeter [Partha & Minski 96] design principle. The latter case study forms an example to the readiness and ease by which design principles are enforced using the patterns wizard. The code sample on Table 2 illustrates the casualness of expressing design principles in the pattern specification language. typesUsed: anA_ConcreteRoutine " Return a collection of A_Type objects of the expressions that are used by qualified calls in anA_ConcreteRoutine" | calls | "First collect all qualified call expressions (unqualified call expressions use class features):" calls := OL_ConstructVisitor dfsAllDescendents: anA_ConcreteRoutine ofRecursiveClass: A_QualifiedCall. ^ calls collect: [ :qualified | qualified subjectExp type]
Table 2: Source code of the Pattern Specification Language (Smalltalk) method that computes the classes of features that appear in qualified calls (obj.feature) within the body of the routine anA_ConcreteRoutine.
References Alexander, Christopher, Sara Ishikawa, Murray Silverstein, Max Jacobson, Ingrid FixdahlKing, and Shlomo Angel (1977). A Pattern Language. Oxford University Press, New York. Coplien, James O. (1994). Software Design Patterns: Common Questions and Answers. A Web article: http://www.research.att.com:80/orgs/ssr/people/cope/index.html Eden, Amnon H, Joseph (Yossi) Gil, and Amiram Yehudai (1996). A Formal Language for Design Patterns (extended abstract). A technical report, The Department of Computer Science, School of Mathematics, Tel Aviv University. Gamma Erich, Richard Helm, Ralph Johnson, and John Vlissides (1995). Design Patterns: Elements of Reusable Object Oriented Software. Addison-Wesley. Pal, Partha P. and Naftali Minski (1996). Imposing the Law of Demeter and Its variations. TOOLS USA 1996.
-4-