1 Design Pattern for Open Class (DRAFT)

Tanaka Akira

A design pattern describes a software architecture which is reusable and exten- sible. [GoF] is the book containing 23 for OOP languages like C++ and Java. [GoF] describes several trade offs of the patterns. In C++ and Java, a class is defined by only one module. However, there are languages which can define a class by two or more modules: Cecil, MultiJava, AspectJ, MixJuice, CLOS, Ruby, etc. Such class is called ”open class” because it is extensible by modules implemented later [Chambers]. For languages with open class, more extensible and/or simpler design patterns exists. We studied design patterns with open class for each GoF design patterns. In this paper, we describe two patterns: the and the Visitor pattern.

2 Abstract Factory

The Abstract Factory pattern is a design pattern for separating class names from the code which generates the object group of related classes for making them configurable. Following figure is the of the Abstract Factory pattern. Since the example described in [GoF] uses only one concrete factory for each binaries, the required concrete factory is selected statically. The example builds two binaries for Motif and Presentation Manager from a single source code. Two concrete factories are exist for Motif and Presentation Manager. When a binary is built, it is selected which concrete factory is linked. Such static selection can be implemented with the fewer number of classes by open class as following modules.

• The module which defines Window and ScrollBar class and their methods which is independent to window systems. • The module which defines methods for the classes which depends on Motif. • The module which defines methods for the classes which depends on Pre- sentation Manager.

There are only two classes. Since they are concrete classes, objects can be in- stantiated directly. So, WidgetFactory and it’s subclasses become unnecessary. In MixJuice, it can be described as follows. module client extends window_system { .... new Window() ...... new ScrollBar() .... }

1 AbstractFactory [WidgetFactory] Client createProductA() [createScrollBar()] AbstractProductA createProductB() [Window] [createWindow()]

ProductA2 ProductA1 [PMWindow] [MotifWindow]

ConcreteFactory1 ConcreteFactory2 [MotifWidgetFactory] [PMWidgetFactory] AbstractProductB createProductA() createProductA() [ScrollBar] [createScrollBar()] [createScrollBar()] createProductB() createProductB() [createWindow()] [createWindow()] ProductB2 ProductB1 [PMScrollBar] [MotifScrollBar]

2 Figure 1: The original Abstract Factory pattern module window_system { define class Window { define abstract Window(); .... } define class ScrollBar { define abstract ScrollBar(); .... } } module motif extends window_system { class Window { Window() {....} .... } class ScrollBar { ScrollBar() {....} .... } } module presentation_manager extends window_system { class Window { Window() {....} .... } class ScrollBar { ScrollBar() {....} .... } }

The binary for Motif is built by the three modules: client, window system and motif. The binary for Presentation Manager is built by the three modules: client, window system and presentation manager. Following figure visualize them as a layered class diagram. Open class can be used in this way in many cases because static selection is typical as pointed by [GoF] as follows,

p.90, line.12-13, 1.Factories as singletons An application typically needs only one instance of a Concrete- Factory per product family.

There are the following advantages the Abstract Factory pattern with open class over usual OOP like C++ and Java.

3 client window_system motif

Window Window

Window() Window()

... new Window() … …new ScrollBar() ... ScrollBar ScrollBar

ScrollBar() ScrollBar()

4 Figure 2: The layered class diagram for the Abstract Factory pattern client window_system presentation_ manager

Window Window

Window() Window()

... new Window() ¼ ¼new ScrollBar() ... ScrollBar ScrollBar

ScrollBar() ScrollBar()

5 Figure 3: The layered class diagram for the Abstract Factory pattern • AbstractFactory and it’s subclasses become unnecessary. Each Product class hierarchy is unified to single class. This reduces classes and makes the system simple, understandable and easier to maintain. • The down cast from AbstractProduct to ConcreteProduct becomes un- necessary. This make the system more type safe. • New product can be introduced by a new module without modifying ex- isting modules.

3 Visitor

The Visitor pattern is a design pattern for separating the structure of objects and a its traverser. Following figure visualize the class diagram of the Visitor pattern. But it is possible to separate them without the Visitor pattern using open class as follows. Because it is possible that methods for the traverser can be introduced to classes which represent the structure by another module. module element { define abstract class Element {....} define class ConcreteElementA extends Element {....} define class ConcreteElementB extends Element {....} } module traverser extends element { class Element { define abstract void traverse(); } class ConcreteElementA { void traverse() {....} } class ConcreteElementB { void traverse() {....} } }

Visitor class and accept methods become unnecessary by open class. This sim- plify the system. Following figure shows the layered class diagram of the above code. However, Visitor class is required for inheriting traversers. When the inher- itance is used for defining traversers, the Visitor pattern can be introduced by another module by open class as follows. In the following example, Concrete- Visitor1a inherits ConcreteVisitor1. module visitor extends element { class Element { define abstract void accept(Visitor v); } class ConcreteElementA { void accept(Visitor v) { v.visit(this); } class ConcreteElementB { void accept(Visitor v) { v.visit(this); }

define class Visitor { define abstract void visit(ConcreteElementA elt); define abstract void visit(ConcreteElementB elt);

6 Client Visitor visitConcreteElementA(ConcreteElementA) visitConcreteElementB(ConcreteElementB)

ConcreteVisitor1 ConcreteVisitor2 visitConcreteElementA(ConcreteElementA) visitConcreteElementA(ConcreteElementA) visitConcreteElementB(ConcreteElementB) visitConcreteElementB(ConcreteElementB)

ObjectStructure Element accept(Visitor)

ConcreteElementA ConcreteElementB accept(Visitor v) accept(Visitor v) operationA() operationB()

v visitConcreteElementA(this) v visitConcreteElementA(this)

7 Figure 4: The original Visitor pattern element traverser

Element Element

traverse()

ConcreteElementA ConcreteElementA

traverse()

ConcreteElementB ConcreteElementB

traverse()

8 Figure 5: The Visitor pattern without Visitor class element visitor Element Element

accept(Visitor)

ConcreteElementA ConcreteElementA

accept(Visitor) v.visit(this); ConcreteElementB ConcreteElementB

accept(Visitor) v.visit(this);

Visitor visit(ConcreteElementA) visit(ConcreteElementB)

ConcreteVisitor1 visit(ConcreteElementA) visit(ConcreteElementB)

ConcreteVisitor1a visit(ConcreteElementA) visit(ConcreteElementB)

9 Figure 6: The Visitor class implementation }

define class ConcreteVisitor1 extends Visitor { void visit(ConcreteElementA elt) {....} void visit(ConcreteElementB elt) {....} }

define class ConcreteVisitor1a extends ConcreteVisitor1 { void visit(ConcreteElementA elt) {....} void visit(ConcreteElementB elt) {....} } }

[GoF] points out the following problem on the Visitor pattern. p.336, line.4, 3.Adding new ConcreteElement classes is hard. The Visitor pattern makes it hard to add new subclasses of Element. Each new Concrete Element gives rise to a new abstract operation on Visitor and a corresponding implementation in every Concrete- Visitor Class. But adding new ConcreteElement classes is easy with open class as folloing figure and follows. module new_concrete_element extends visitor { define class ConcreteElementC extends Element { .... void accept(Visitor v) { v.visit(this); } }

class Visitor { define abstract void visit(ConcreteElementC elt); }

class ConcreteVisitor1 { void visit(ConcreteElementC elt) {....} }

define class ConcreteVisitor1a { void visit(ConcreteElementC elt) {....} } }

There are the following advantages on the Visitor pattern with open class over usual OOP like C++ and Java. If a traverser definition doesn’t require inheritance, • The Visitor pat- tern becomes unnecessary and the program is simplified.

10 element visitor new_concrete_element

Element Element

accept(Visitor)

ConcreteElementA ConcreteElementA ConcreteElementC

accept(Visitor) v.visit(this); accept(Visitor) v.visit(this);

ConcreteElementB ConcreteElementB

accept(Visitor) v.visit(this);

Visitor Visitor visit(ConcreteElementA) visit(ConcreteElementC) visit(ConcreteElementB)

ConcreteVisitor1 ConcreteVisitor1 visit(ConcreteElementA) visit(ConcreteElementC) visit(ConcreteElementB)

ConcreteVisitor1a ConcreteVisitor1a

visit(ConcreteElementA) visit(ConcreteElementC) visit(ConcreteElementB)

11 Figure 7: New ConcreteElement for the Visitor pattern Table 1: the open class effect on each design pattern

design pattern classes intro. ext. type safety simp. mechanism Abstract Factory differ. X X p.90 method imp., field add. Builder differ. X method imp., field add. Factory Method differ. X X method imp. Prototype same p.120 method add. Singleton differ. p.128 class method overridden Adapter differ. p.143 interface add. Bridge differ. X X method/field add. Composite none Decorator none Facade differ. X class method add. Flyweight none Proxy none Chain of Responsibility same X p.241 X X method add. Command none Interpreter same X X same Mediator none Memento same Observer same X X method/field add., method overridden State none Strategy same p.318 method add. Template Method same p.329 X method add. Visitor differ. X method add. same X p.336 method add.

If a traverser definition require inheritance, • the Visitor pattern can be introduced by new module without modification of modules im- plementing object structures and • new ConcreteElement class can be introduced without the modifica- tion. Thus, the design of a module which implement object structures can ignore traversers since traversers can be implemented freely by other modules with open class. It means that open class makes the module design more abstract.

4 23 GoF design patterns with open class

The following table summarize the effect on each design pattern by open class. The meaning of each columns are described follows.

12 classes ”same” means that there are some advantages of open class on the design pattern and class diagram after all modules are merged is same as GoF design pattern. ”differ.” means that there are some advantages of open class on the design pattern and class diagram after all modules are merged is different from GoF design pattern. ”none” means that we couldn’t find any advantages of open class on the design pattern. For example, we described the pattern using different class diagram at first and the pattern using same class diagram later with the Visitor pattern in previous section. intro. (introduction) This column means that the design pattern is imple- mentable for existing classes. For example, can be im- plemented by adding a field and its accessor to a subject class for list of observers. ext. (extension) This column means that another extension way is available. For example, the Visitor pattern can introduce new concrete element by open class. type safety This column means the down cast decreasement. For example, Factory Method returns a object as the type of an abstract class. So, a down cast is required to call the method of a concrete class. If the concrete class is only one, the abstract and concrete class is unifiable and down cast becomes unnecessary by open class. simp. (simplification) This column means the decreasement of number of classes. For example, can be implemented by adding super interface with introducing no new classes.

5 Conclusion

Thanks to open class, single class can be defined by two or more modules. It makes possible to modify classes defined by existing modules. This property can be used for various extension. We studied open class with GoF design patterns and described the Abstract Factory pattern and the Visitor pattern. Design patterns can be more extensible and simple by open class. Generally, open class is useful if a structure is determined statically.

6 References

[Chambers] Curtis Clifton, Gary T. Leavens, Craig Chambers, and Todd Mill- stein. MultiJava: modular open classes and symmetric for Java. Proc. of the OOPSLA2000, pages 130-145, October 2000. Published as ACM SIGPLAN Notices, volume 35, number 10. [GoF] E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns. Addison-Welsley, 1995.

13