Design Patterns Abap Objects

December 23, 2016 | Author: cesanne1 | Category: N/A
Share Embed Donate


Short Description

Download Design Patterns Abap Objects...

Description

Design Patterns

Implementation Of objects using design patterns in Abap Object

Version: 1 Date: 2. Januar 2008

Project: Design Pattern

Version management Date

What has changed

Sections

Whom

Version

01.12.2007

Creation of the document

All

BGS

1.0

Reference documents Document

Version

The Gang Of Four

Participants Name

Company

Benny G. Sørensen

BGS Consulting ApS

Version: 1.0 Side: ii

Roll in the project

Location

Project: Design Pattern Contents: 1

INTRODUCTION

6

2

DESIGN PATTERNS

6

2.1 CREATIONAL PATTERNS 2.1.1 Abstract Factory 2.1.1.1 2.1.1.2 2.1.1.3 2.1.1.4 2.1.1.5 2.1.1.6 2.1.1.7 2.1.1.8

2.1.2

2.1.3

2.1.5

Version: 1.0 Side: 3

34 34 35 35 35 40 42 44

47 47 47 48 48 48 50 52 54

57

Definition Common Use Implementation UML class diagram Participants Sample code In C# Sample code In ABAP Sample code In C# Sample code In ABAP Sample code In ABAP for Application

2.2 STRUCTURAL PATTERNS 2.2.1 Adapter 2.2.1.1 2.2.1.2 2.2.1.3 2.2.1.4

21 21 22 22 22 25 27 31

Definition Used for UML class diagram Participants Sample code In C# Sample code In ABAP Sample code In C# Sample code In ABAP

Singleton

2.1.5.1 2.1.5.2 2.1.5.3 2.1.5.4 2.1.5.5 2.1.5.6 2.1.5.7 2.1.5.8 2.1.5.9 2.1.5.10

21

Definition UML class diagram Participants Sample code In C# Sample code in ABAP Sample code in ABAP Sample code in ABAP

Prototype

2.1.4.1 2.1.4.2 2.1.4.3 2.1.4.4 2.1.4.5 2.1.4.6 2.1.4.7 2.1.4.8

7 8 10 10 10 13 16 18

Definition Useful tips UML class diagram Participants Sample code In C# Sample code In ABAP Sample code In C# Sample code In ABAP

Factory Method

2.1.3.1 2.1.3.2 2.1.3.3 2.1.3.4 2.1.3.5 2.1.3.6 2.1.3.7

2.1.4

Definition Commen Use UML class diagram Participants Sample code in C# Sample code in ABAP Sample code in C# Sample code in ABAP

Builder

2.1.2.1 2.1.2.2 2.1.2.3 2.1.2.4 2.1.2.5 2.1.2.6 2.1.2.7 2.1.2.8

7 7

Definition Common Use UML class diagram Participants

57 57 58 59 59 59 60 62 64 66

67 67 67 68 69 69

Project: Design Pattern 2.2.1.5 2.2.1.6 2.2.1.7 2.2.1.8 2.2.1.9

2.2.2

Bridge

2.2.2.1 2.2.2.2 2.2.2.3 2.2.2.4 2.2.2.5

2.2.3

2.2.5

2.2.6

2.2.7

Version: 1.0 Side: 4

96 96 97 97 97 99 102 105

110 110 110 110 111 113 116 118

122 122 122 122 123 124 127

130

Definition UML class diagram Participants Sample code In C# Sample code In ABAP Sample code In C# Sample code In ABAP using interface

2.3 BEHAVIORAL PATTERNS 2.3.1 Chain of Resp. 2.3.1.1 2.3.1.2 2.3.1.3 2.3.1.4 2.3.1.5 2.3.1.6

84 85 85 85 88 91 93

Definition UML class diagram Participants Sample code In C# Sample code In ABAP Sample code In C#

Proxy

2.2.7.1 2.2.7.2 2.2.7.3 2.2.7.4 2.2.7.5 2.2.7.6 2.2.7.7

84

Definition UML class diagram Participants Sample code In C# Sample code In ABAP Sample code In C# Sample code In ABAP

Flyweight (fluevægt)

2.2.6.1 2.2.6.2 2.2.6.3 2.2.6.4 2.2.6.5 2.2.6.6

83 83 84 84 84

Definition UML class diagram Participants Sample code In C# Sample code In ABAP Sample code In C# Sample code In ABAP

Facade

2.2.5.1 2.2.5.2 2.2.5.3 2.2.5.4 2.2.5.5 2.2.5.6 2.2.5.7

83

Definition UML class diagram Participants Sample code In C# Sample code In ABAP Sample code In C# Sample code In ABAP

Decorator

2.2.4.1 2.2.4.2 2.2.4.3 2.2.4.4 2.2.4.5 2.2.4.6 2.2.4.7

69 70 72 75 79

Definition Common Use UML class diagram Participants Sample code In C#

Composite

2.2.3.1 2.2.3.2 2.2.3.3 2.2.3.4 2.2.3.5 2.2.3.6 2.2.3.7

2.2.4

Sample code In C# Sample code In ABAP Sample code In C# Sample code In ABAP Sample code In ABAP using interfaces

Definition UML class diagram Participants Sample code In C# Sample code In ABAP Sample code In C#

130 131 131 131 133 135 136

139 139 139 140 140 140 142 146

Project: Design Pattern 2.3.1.7

2.3.2

2.3.2.1 2.3.2.2 2.3.2.3 2.3.2.4 2.3.2.5 2.3.2.6 2.3.2.7

2.3.3

2.3.5

2.3.6

2.3.7

2.3.8

2.3.9

2.3.10 2.3.10.1 2.3.10.2 2.3.10.3 2.3.10.4

2.3.11 2.3.11.1 2.3.11.2 2.3.11.3 2.3.11.4

Version: 1.0 Side: 5

180 180 181 181 181

187 187 187 187 187

192 192 193 193 193

198

Definition UML class diagram Participants Sample code I C#

Strategy

2.3.9.1 2.3.9.2 2.3.9.3 2.3.9.4

174 174 174 175

Definition UML class diagram Participants Sample code I C#

State

2.3.8.1 2.3.8.2 2.3.8.3 2.3.8.4

174

Definition UML class diagram Participants Sample code I C#

Observer

2.3.7.1 2.3.7.2 2.3.7.3 2.3.7.4

169 169 169 170

Definition UML class diagram Participants Sample code I C#

Memento

2.3.6.1 2.3.6.2 2.3.6.3 2.3.6.4

169

Definition UML class diagram Participants Sample code I C#

Mediator

2.3.5.1 2.3.5.2 2.3.5.3 2.3.5.4

154 155 155 155 157 160 163

Definition UML class diagram Participants Sample code I C#

Iterator

2.3.4.1 2.3.4.2 2.3.4.3 2.3.4.4

149

154

Definition UML class diagram Participants Sample code In C# Sample code in ABAP Sample code In C# Sample code In C#

Interpreter

2.3.3.1 2.3.3.2 2.3.3.3 2.3.3.4

2.3.4

Sample code In ABAP

Command

198 198 199 199

206

Definition UML class diagram Participants Sample code In C#

Template Method

206 207 207 207

211

Definition UML class diagram Participants Sample code In C#

Visitor Definition UML class diagram Participants Sample code In C#

211 212 212 212

216 216 217 217 218

Project: Design Pattern

1 Introduction 2 Design Patterns Design patterns are recurring solutions to software design problems you find again and again in real-world application development. Patterns are about design and interaction of objects, as well as providing a communication platform concerning elegant, reusable solutions to commonly encountered programming challenges.

These design patterns have been copied from The Gang of Four homepage. The Gang of Four (GoF) patterns are generally considered the foundation for all other patterns. They are categorized in three groups: Creational, Structural, and Behavioral. Here you will find information on these important patterns. To give you a head start, the C# source code is provided in 2 forms: 'structural' and 'real-world'. Structural code uses type names as defined in the pattern definition and UML diagrams. Real-world code provides real-world programming situations where you may use these patterns. A third form, 'ABAP Object' demonstrates design patterns that exploit SAP R/3 built-in ABAP Object’s features. Creational Patterns Abstract Factory

Creates an instance of several families of classes

Builder

Separates object construction from its representation

Factory Method

Creates an instance of several derived classes

Prototype

A fully initialized instance to be copied or cloned

Singleton

A class of which only a single instance can exist

Structural Patterns Adapter

Match interfaces of different classes

Bridge

Separates an object’s interface from its implementation

Composite

A tree structure of simple and composite objects

Decorator

Add responsibilities to objects dynamically

Facade

A single class that represents an entire subsystem

Version: 1.0 Side: 6

Project: Design Pattern

Flyweight

A fine-grained instance used for efficient sharing

Proxy

An object representing another object

Behavioral Patterns Chain of Resp.

A way of passing a request between a chain of objects

Command

Encapsulate a command request as an object

Interpreter

A way to include language elements in a program

Iterator

Sequentially access the elements of a collection

Mediator

Defines simplified communication between classes

Memento

Capture and restore an object's internal state

Observer

A way of notifying change to a number of classes

State

Alter an object's behavior when its state changes

Strategy

Encapsulates an algorithm inside a class

Template Method

Defer the exact steps of an algorithm to a subclass

Visitor

Defines a new operation to a class without change

2.1 Creational Patterns 2.1.1 Abstract Factory Creates an instance of several families of classes

2.1.1.1 Definition Provide an interface for creating families of related or dependent objects without specifying their concrete classes A software design pattern, the Abstract Factory Pattern provides a way to encapsulate a group of individual factories that have a common theme. In normal usage, the client software would create a concrete implementation of the abstract factory and then use the generic interfaces to create the concrete objects that are part of the theme. The client does not know (nor care) about which concrete objects it gets from each of these internal factories since it uses only the generic interfaces of their products. This pattern separates the details of implementation of a set of objects from its general usage.

Version: 1.0 Side: 7

Project: Design Pattern An example of this would be an abstract factory class DocumentCreator that provides interfaces to create a number of products (eg. createLetter() and createResume()). The system would have any number of derived concrete versions of the DocumentCreator class like FancyDocumentCreator or ModernDocumentCreator, each with a different implementation of createLetter() and createResume() that would create a corresponding object like FancyLetter or ModernResume. Each of these products is derived from a simple abstract class like Letter or Resume of which the client is aware. The client code would get an appropriate instantiation of the DocumentCreator and call its factory methods. Each of the resulting objects would be created from the same DocumentCreator implementation and would share a common theme (they would all be fancy or modern objects). The client would need to know how to handle only the abstract Letter or Resume class, not the specific version that it got from the concrete factory. In software development, a Factory is the location in the code at which objects are constructed. The intent in employing the pattern is to insulate the creation of objects from their usage. This allows for new derived types to be introduced with no change to the code that uses the base class. Use of this pattern makes it possible to interchange concrete classes without changing the code that uses them, even at runtime. However, employment of this pattern, as with similar design patterns, incurs the risk of unnecessary complexity and extra work in the initial writing of code.

2.1.1.2 Commen Use The factory determines the actual concrete type of object to be created, and it is here that the object is actually created (in C++, for instance, by the new operator). However, the factory only returns an abstract pointer to the created concrete object. This insulates client code from object creation by having clients ask a factory object to create an object of the desired abstract type and to return an abstract pointer to the object. As the factory only returns an abstract pointer, the client code (which requested the object from the factory) does not know - and is not burdened by - the actual concrete type of the object which was just created. However, the type of a concrete object (and hence a concrete factory) is known by the abstract factory; for instance, the factory may read it from a configuration file. The client has no need to specify the type, since it has already been specified in the configuration file. In particular, this means:

Version: 1.0 Side: 8

Project: Design Pattern •

The client code has no knowledge whatsoever of the concrete type, not needing to include any header files or class declarations relating to the concrete type. The client code deals only with the abstract type. Objects of a concrete type are indeed created by the factory, but the client code accesses such objects only through their abstract interface.



Adding new concrete types is done by modifying the client code to use a different factory, a modification which is typically one line in one file. (The different factory then creates objects of a different concrete type, but still returns a pointer of the same abstract type as before - thus insulating the client code from change.) This is significantly easier than modifying the client code to instantiate a new type, which would require changing every location in the code where a new object is created (as well as making sure that all such code locations also have knowledge of the new concrete type, by including for instance a concrete class header file). If all factory objects are stored globally in a singleton object, and all client code goes through the singleton to access the proper factory for object creation, then changing factories is as easy as changing the singleton object.

The class diagram of this design pattern is as shown

Version: 1.0 Side: 9

Project: Design Pattern

2.1.1.3 UML class diagram

2.1.1.4 Participants The classes and/or objects participating in this pattern are: • AbstractFactory (ContinentFactory) declares an interface for operations that create abstract products • ConcreteFactory (AfricaFactory, AmericaFactory) implements the operations to create concrete product objects • AbstractProduct (Herbivore, Carnivore) declares an interface for a type of product object • Product (Wildebeest, Lion, Bison, Wolf) defines a product object to be created by the corresponding concrete factory implements the AbstractProduct interface • Client (AnimalWorld) uses interfaces declared by AbstractFactory and AbstractProduct classes

2.1.1.5 Sample code in C# This structural code demonstrates the Abstract Factory pattern creating parallel hierarchies of objects. Object creation has been abstracted and there is no need for hard-coded class names in the client code. // Abstract Factory pattern -- Structural example

Version: 1.0 Side: 10

Project: Design Pattern using System; namespace DoFactory.GangOfFour.Abstract.Structural { // MainApp test application class MainApp { public static void Main() { // Abstract factory #1 AbstractFactory factory1 = new ConcreteFactory1(); Client c1 = new Client(factory1); c1.Run(); // Abstract factory #2 AbstractFactory factory2 = new ConcreteFactory2(); Client c2 = new Client(factory2); c2.Run(); // Wait for user input Console.Read(); } } // "AbstractFactory" abstract class AbstractFactory { public abstract AbstractProductA CreateProductA(); public abstract AbstractProductB CreateProductB(); } // "ConcreteFactory1" class ConcreteFactory1 : AbstractFactory { public override AbstractProductA CreateProductA() { return new ProductA1(); } public override AbstractProductB CreateProductB() { return new ProductB1(); } } // "ConcreteFactory2" class ConcreteFactory2 : AbstractFactory { public override AbstractProductA CreateProductA() { return new ProductA2(); } public override AbstractProductB CreateProductB() Version: 1.0 Side: 11

Project: Design Pattern { return new ProductB2(); } } // "AbstractProductA" abstract class AbstractProductA { } // "AbstractProductB" abstract class AbstractProductB { public abstract void Interact(AbstractProductA a); } // "ProductA1" class ProductA1 : AbstractProductA { } // "ProductB1" class ProductB1 : AbstractProductB { public override void Interact(AbstractProductA a) { Console.WriteLine(this.GetType().Name + " interacts with " + a.GetType().Name); } } // "ProductA2" class ProductA2 : AbstractProductA { } // "ProductB2" class ProductB2 : AbstractProductB { public override void Interact(AbstractProductA a) { Console.WriteLine(this.GetType().Name + " interacts with " + a.GetType().Name); } } // "Client" - the interaction environment of the products class Client { Version: 1.0 Side: 12

Project: Design Pattern private AbstractProductA AbstractProductA; private AbstractProductB AbstractProductB; // Constructor public Client(AbstractFactory factory) { AbstractProductB = factory.CreateProductB(); AbstractProductA = factory.CreateProductA(); } public void Run() { AbstractProductB.Interact(AbstractProductA); } } }

Output ProductB1 interacts with ProductA1 ProductB2 interacts with ProductA2

2.1.1.6 Sample code in ABAP This structural code demonstrates the Abstract Factory pattern creating parallel hierarchies of objects. Object creation has been abstracted and there is no need for hard-coded class names in the client code. In ABAP you should consider using interfaces instead of abstract classes. REPORT ZABSTRACTFACTORY_STRUCTURAL NO STANDARD PAGE HEADING LINE-SIZE 80. CLASS cl_abap_typedescr DEFINITION LOAD. DATA: moff TYPE i ,slen TYPE i ,mlen TYPE i. DEFINE ?get_class_name. &2 = cl_abap_classdescr=>get_class_name( &1 ). find regex 'CLASS=' in &2 match offset moff match length mlen. slen = moff + mlen. shift &2 by slen places left. END-OF-DEFINITION. CLASS abstractproducta DEFINITION ABSTRACT. ENDCLASS. "abstractproducta DEFINITION CLASS abstractproductb DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: interact ABSTRACT IMPORTING a TYPE REF TO abstractproducta . ENDCLASS. "abstractproductb DEFINITION CLASS abstractproductb IMPLEMENTATION. ENDCLASS. "abstractproductb IMPLEMENTATION CLASS producta1 DEFINITION INHERITING FROM abstractproducta. ENDCLASS. "producta1 DEFINITION CLASS productb1 DEFINITION INHERITING FROM abstractproductb.

Version: 1.0 Side: 13

Project: Design Pattern PUBLIC SECTION. METHODS: interact REDEFINITION. ENDCLASS. "productb1 DEFINITION CLASS productb1 IMPLEMENTATION. METHOD interact. DATA: class_name_me TYPE abap_abstypename ,class_name_a TYPE abap_abstypename. ?get_class_name me class_name_me. ?get_class_name a class_name_a. WRITE: / class_name_me ,'Interact with ' ,class_name_a. ENDMETHOD. "interact ENDCLASS. "productb1 IMPLEMENTATION CLASS producta2 DEFINITION INHERITING FROM abstractproducta. ENDCLASS. "producta2 DEFINITION CLASS productb2 DEFINITION INHERITING FROM abstractproductb. PUBLIC SECTION. METHODS: interact REDEFINITION. ENDCLASS. "productb2 DEFINITION CLASS productb2 IMPLEMENTATION. METHOD interact. DATA: class_name_me TYPE abap_abstypename ,class_name_a TYPE abap_abstypename. ?get_class_name me class_name_me. ?get_class_name a class_name_a. WRITE: / class_name_me ,'Interact with ' ,class_name_a. ENDMETHOD. "interact ENDCLASS. "productb2 IMPLEMENTATION CLASS abstractfactory DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: createproducta ABSTRACT RETURNING value(producta) TYPE REF TO abstractproducta ,createproductb ABSTRACT RETURNING value(productb) TYPE REF TO abstractproductb . ENDCLASS. "abstractfactory DEFINITION CLASS concretefactory1 DEFINITION INHERITING FROM abstractfactory. PUBLIC SECTION. METHODS: createproducta REDEFINITION ,createproductb REDEFINITION . ENDCLASS. "concretefactory1 DEFINITION CLASS concretefactory1 IMPLEMENTATION. METHOD createproducta. CREATE OBJECT producta TYPE producta1. ENDMETHOD. "createproducta METHOD createproductb. CREATE OBJECT productb TYPE productb1. ENDMETHOD. "createproductb ENDCLASS. "concretefactory1 IMPLEMENTATION CLASS concretefactory2 DEFINITION INHERITING FROM abstractfactory. PUBLIC SECTION. Version: 1.0 Side: 14

Project: Design Pattern METHODS: createproducta REDEFINITION ,createproductb REDEFINITION . ENDCLASS. "concretefactory2 DEFINITION CLASS concretefactory2 IMPLEMENTATION. METHOD createproducta. CREATE OBJECT producta TYPE producta2. ENDMETHOD. "createproducta METHOD createproductb. CREATE OBJECT productb TYPE productb2. ENDMETHOD. "createproductb ENDCLASS. "concretefactory1 IMPLEMENTATION CLASS client DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING factory TYPE REF TO abstractfactory ,run . PROTECTED SECTION. DATA: abstractproducta TYPE REF TO abstractproducta ,abstractproductb TYPE REF TO abstractproductb . ENDCLASS. "client DEFINITION CLASS client IMPLEMENTATION. METHOD constructor. abstractproducta = factory->createproducta( ). abstractproductb = factory->createproductb( ). ENDMETHOD. "constructor METHOD run. abstractproductb->interact( abstractproducta ). ENDMETHOD. "run ENDCLASS. "client IMPLEMENTATION CLASS mainapp DEFINITION. PUBLIC SECTION. * CLASS-DATA: oa_creator_coll TYPE TABLE OF REF TO creator. CLASS-METHODS main. ENDCLASS. "mainapp DEFINITION CLASS mainapp IMPLEMENTATION. METHOD main. DATA: factory1 TYPE REF TO ,factory2 TYPE REF TO ,c1 TYPE REF TO ,c2 TYPE REF TO .

concretefactory1 concretefactory2 client client

CREATE OBJECT factory1. CREATE OBJECT c1 EXPORTING factory = factory1 . CALL METHOD c1->run( ). CREATE OBJECT factory2. CREATE OBJECT c2 EXPORTING factory = factory2. CALL METHOD c2->run( ). ENDMETHOD. ENDCLASS. START-OF-SELECTION. mainapp=>main( ). Version: 1.0 Side: 15

"main "mainapp IMPLEMENTATION

Project: Design Pattern

Output PRODUCTB1 Interact with PRODUCTA1 PRODUCTB2 Interact with PRODUCTA2

2.1.1.7 Sample code in C# This real-world code demonstrates the creation of different animal worlds for a computer game using different factories. Although the animals created by the Continent factories are different, the interactions among the animals remain the same. // Abstract Factory pattern -- Real World example using System; namespace DoFactory.GangOfFour.Abstract.RealWorld { // MainApp test application class MainApp { public static void Main() { // Create and run the Africa animal world ContinentFactory africa = new AfricaFactory(); AnimalWorld world = new AnimalWorld(africa); world.RunFoodChain(); // Create and run the America animal world ContinentFactory america = new AmericaFactory(); world = new AnimalWorld(america); world.RunFoodChain(); // Wait for user input Console.Read(); } } // "AbstractFactory" abstract class ContinentFactory { public abstract Herbivore CreateHerbivore(); public abstract Carnivore CreateCarnivore(); } // "ConcreteFactory1" class AfricaFactory : ContinentFactory { public override Herbivore CreateHerbivore() { Version: 1.0 Side: 16

Project: Design Pattern return new Wildebeest(); } public override Carnivore CreateCarnivore() { return new Lion(); } } // "ConcreteFactory2" class AmericaFactory : ContinentFactory { public override Herbivore CreateHerbivore() { return new Bison(); } public override Carnivore CreateCarnivore() { return new Wolf(); } } // "AbstractProductA" abstract class Herbivore { } // "AbstractProductB" abstract class Carnivore { public abstract void Eat(Herbivore h); } // "ProductA1" class Wildebeest : Herbivore { } // "ProductB1" class Lion : Carnivore { public override void Eat(Herbivore h) { // Eat Wildebeest Console.WriteLine(this.GetType().Name + " eats " + h.GetType().Name); } } // "ProductA2" class Bison : Herbivore Version: 1.0 Side: 17

Project: Design Pattern { } // "ProductB2" class Wolf : Carnivore { public override void Eat(Herbivore h) { // Eat Bison Console.WriteLine(this.GetType().Name + " eats " + h.GetType().Name); } } // "Client" class AnimalWorld { private Herbivore herbivore; private Carnivore carnivore; // Constructor public AnimalWorld(ContinentFactory factory) { carnivore = factory.CreateCarnivore(); herbivore = factory.CreateHerbivore(); } public void RunFoodChain() { carnivore.Eat(herbivore); } } }

Output Lion eats Wildebeest Wolf eats Bison

2.1.1.8 Sample code in ABAP This real-world code demonstrates the creation of different animal worlds for a computer game using different factories. Although the animals created by the Continent factories are different, the interactions among the animals remain the same. You should however consider using interfaces instead of abstract classes. REPORT zabstractfactory_realworld NO STANDARD PAGE HEADING LINE-SIZE 80. CLASS cl_abap_typedescr DEFINITION LOAD. DATA: moff TYPE i ,slen TYPE i ,mlen TYPE i. DEFINE ?get_class_name.

Version: 1.0 Side: 18

Project: Design Pattern &2 = cl_abap_classdescr=>get_class_name( &1 ). find regex 'CLASS=' in &2 match offset moff match length mlen. slen = moff + mlen. shift &2 by slen places left. END-OF-DEFINITION. CLASS herbivore DEFINITION ABSTRACT. ENDCLASS. "herbivore DEFINITION CLASS carnivore DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: eat ABSTRACT IMPORTING a TYPE REF TO herbivore . ENDCLASS. "carnivore DEFINITION CLASS carnivore IMPLEMENTATION. ENDCLASS. "carnivore IMPLEMENTATION CLASS wildebeest DEFINITION INHERITING FROM herbivore. ENDCLASS. "wildebeest DEFINITION CLASS lion DEFINITION INHERITING FROM carnivore. PUBLIC SECTION. METHODS: eat REDEFINITION. ENDCLASS. "Lion DEFINITION CLASS lion IMPLEMENTATION. METHOD eat. DATA: class_name_me TYPE abap_abstypename ,class_name_a TYPE abap_abstypename. ?get_class_name me class_name_me. ?get_class_name a class_name_a. WRITE: / class_name_me ,' eats ' ,class_name_a. ENDMETHOD. "interact ENDCLASS. "Lion IMPLEMENTATION CLASS bison DEFINITION INHERITING FROM herbivore. ENDCLASS. "Bison DEFINITION CLASS wolf DEFINITION INHERITING FROM carnivore. PUBLIC SECTION. METHODS: eat REDEFINITION. ENDCLASS. "Wolf DEFINITION CLASS wolf IMPLEMENTATION. METHOD eat. DATA: class_name_me TYPE abap_abstypename ,class_name_a TYPE abap_abstypename. ?get_class_name me class_name_me. ?get_class_name a class_name_a. WRITE: / class_name_me ,' eats ' ,class_name_a. ENDMETHOD. "interact ENDCLASS. "Wolf IMPLEMENTATION CLASS continentfactory DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: createherbivore ABSTRACT RETURNING value(herbivore) TYPE REF TO herbivore ,createcarnivore ABSTRACT RETURNING value(carnivore) TYPE REF TO carnivore . Version: 1.0 Side: 19

Project: Design Pattern ENDCLASS.

"ContinentFactory DEFINITION

CLASS africafactory DEFINITION INHERITING FROM continentfactory. PUBLIC SECTION. METHODS: createherbivore REDEFINITION ,createcarnivore REDEFINITION . ENDCLASS. "ContinentFactory DEFINITION CLASS africafactory IMPLEMENTATION. METHOD createherbivore. CREATE OBJECT herbivore TYPE wildebeest. ENDMETHOD. "createproducta METHOD createcarnivore. CREATE OBJECT carnivore TYPE lion. ENDMETHOD. "createproductb ENDCLASS. "ContinentFactory IMPLEMENTATION

CLASS americafactory DEFINITION INHERITING FROM continentfactory. PUBLIC SECTION. METHODS: createherbivore REDEFINITION ,createcarnivore REDEFINITION . ENDCLASS. "concretefactory2 DEFINITION CLASS americafactory IMPLEMENTATION. METHOD createherbivore. CREATE OBJECT herbivore TYPE bison. ENDMETHOD. "createproducta METHOD createcarnivore. CREATE OBJECT carnivore TYPE wolf. ENDMETHOD. "createproductb ENDCLASS. "ContinentFactory IMPLEMENTATION CLASS animalworld DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING factory TYPE REF TO continentfactory ,runfoodchain . PROTECTED SECTION. DATA: herbivore TYPE REF TO herbivore ,carnivore TYPE REF TO carnivore . ENDCLASS. "Animalworld DEFINITION CLASS animalworld IMPLEMENTATION. METHOD constructor. herbivore = factory->createherbivore( ). carnivore = factory->createcarnivore( ). ENDMETHOD. "constructor METHOD runfoodchain. carnivore->eat( herbivore ). ENDMETHOD. "Runfoodchain ENDCLASS. "Animalworld IMPLEMENTATION CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS main. ENDCLASS. Version: 1.0 Side: 20

"mainapp DEFINITION

Project: Design Pattern

CLASS mainapp IMPLEMENTATION. METHOD main. DATA: africa TYPE REF TO africafactory ,america TYPE REF TO americafactory ,world TYPE REF TO animalworld . CREATE OBJECT africa. CREATE OBJECT world EXPORTING factory = africa . CALL METHOD world->runfoodchain( ). CREATE OBJECT america. CREATE OBJECT world EXPORTING factory = america. CALL METHOD world->runfoodchain( ). ENDMETHOD. ENDCLASS.

"main "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ). Output LION eats WILDEBEEST WOLF eats BISON

2.1.2 Builder Separates object construction from its representation

2.1.2.1 Definition Separate the construction of a complex object from its representation so that the same construction process can create different representations. The Builder Pattern is a software design pattern. The intention is to separate the construction of a complex object from its representation so that the same construction process can create different representations. Often, Builder Pattern builds Composite pattern, a structure pattern.

2.1.2.2 Useful tips •

Sometimes creational patterns are complementary: Builder can use one of the other patterns to implement which components get built. Abstract Factory, Builder, and Prototype can use Singleton in their implementations.



Builder focuses on constructing a complex object step by step. Abstract Factory emphasizes a family of product objects (either simple or complex). Builder returns the product as a final step, but as far as the

Version: 1.0 Side: 21

Project: Design Pattern Abstract Factory is concerned, the product gets returned immediately. •

Builder often builds a Composite.



Often, designs start out using Factory Method (less complicated, more customizable, subclasses proliferate) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, more complex) as the designer discovers where more flexibility is needed.

2.1.2.3 UML class diagram

2.1.2.4 Participants The classes and/or objects participating in this pattern are: • Builder (VehicleBuilder) o specifies an abstract interface for creating parts of a Product object • ConcreteBuilder (MotorCycleBuilder, CarBuilder, ScooterBuilder) o constructs and assembles parts of the product by implementing the Builder interface defines and keeps track of the representation it creates provides an interface for retrieving the product • Director (Shop) o constructs an object using the Builder interface • Product (Vehicle) o represents the complex object under construction. ConcreteBuilder builds the product's internal representation and defines the process by which it's assembled includes classes that define the constituent parts, including interfaces for assembling the parts into the final result

2.1.2.5 Sample code In C# This structural code demonstrates the Builder pattern in which complex objects are created in a step-by-step fashion. The construction process can create different object representations and provides a high level of control over the assembly of the objects. // Builder pattern -- Structural example Version: 1.0 Side: 22

Project: Design Pattern

using System; using System.Collections; namespace DoFactory.GangOfFour.Builder.Structural { // MainApp test application public class MainApp { public static void Main() { // Create director and builders Director director = new Director(); Builder b1 = new ConcreteBuilder1(); Builder b2 = new ConcreteBuilder2(); // Construct two products director.Construct(b1); Product p1 = b1.GetResult(); p1.Show(); director.Construct(b2); Product p2 = b2.GetResult(); p2.Show(); // Wait for user Console.Read(); } } // "Director" class Director { // Builder uses a complex series of steps public void Construct(Builder builder) { builder.BuildPartA(); builder.BuildPartB(); } } // "Builder" abstract { public public public }

class Builder abstract void BuildPartA(); abstract void BuildPartB(); abstract Product GetResult();

// "ConcreteBuilder1" class ConcreteBuilder1 : Builder Version: 1.0 Side: 23

Project: Design Pattern { private Product product = new Product(); public override void BuildPartA() { product.Add("PartA"); } public override void BuildPartB() { product.Add("PartB"); } public override Product GetResult() { return product; } } // "ConcreteBuilder2" class ConcreteBuilder2 : Builder { private Product product = new Product(); public override void BuildPartA() { product.Add("PartX"); } public override void BuildPartB() { product.Add("PartY"); } public override Product GetResult() { return product; } } // "Product" class Product { ArrayList parts = new ArrayList(); public void Add(string part) { parts.Add(part); } public void Show() { Console.WriteLine("\nProduct Parts -------"); foreach (string part in parts) Version: 1.0 Side: 24

Project: Design Pattern Console.WriteLine(part); } } }

Output Product Parts ------PartA PartB Product Parts ------PartX PartY

2.1.2.6 Sample code In ABAP This structural code demonstrates the Builder pattern in which complex objects are created in a step-by-step fashion. The construction process can create different object representations and provides a high level of control over the assembly of the objects. REPORT

zbuilder_structural NO STANDARD PAGE HEADING LINE-SIZE 80.

CLASS product DEFINITION. PUBLIC SECTION. DATA: parts TYPE TABLE OF string. METHODS: add IMPORTING part TYPE string ,show. ENDCLASS. "product DEFINITION CLASS product IMPLEMENTATION. METHOD add. APPEND part TO parts. ENDMETHOD.

"add

METHOD show. DATA: parts_line TYPE string. WRITE: / 'Product Parts --------'. LOOP AT parts INTO parts_line. WRITE: / parts_line. ENDLOOP. ENDMETHOD. "show ENDCLASS. "product IMPLEMENTATION CLASS builder DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: buildparta ABSTRACT ,buildpartb ABSTRACT ,getresult ABSTRACT RETURNING value(product) TYPE REF TO product. ENDCLASS. "builder DEFINITION CLASS concretebuilder1 DEFINITION INHERITING FROM builder. PUBLIC SECTION. METHODS: constructor ,buildparta REDEFINITION ,buildpartb REDEFINITION ,getresult REDEFINITION Version: 1.0 Side: 25

Project: Design Pattern . PRIVATE SECTION. DATA: product TYPE REF TO product. ENDCLASS. "concretebuilder1 DEFINITION CLASS concretebuilder1 IMPLEMENTATION. METHOD constructor. CALL METHOD super->constructor. CREATE OBJECT me->product. ENDMETHOD. "constructor METHOD buildparta. product->add('PartA'). ENDMETHOD. "buildparta METHOD buildpartb. product->add('Partb'). ENDMETHOD. "buildpartb METHOD getresult. product = me->product. ENDMETHOD. "getresult ENDCLASS. "concretebuilder1 IMPLEMENTATION CLASS concretebuilder2 DEFINITION INHERITING FROM builder. PUBLIC SECTION. METHODS: constructor ,buildparta REDEFINITION ,buildpartb REDEFINITION ,getresult REDEFINITION . PRIVATE SECTION. DATA: product TYPE REF TO product. ENDCLASS. "concretebuilder2 DEFINITION CLASS concretebuilder2 IMPLEMENTATION. METHOD constructor. CALL METHOD super->constructor. CREATE OBJECT me->product. ENDMETHOD. "constructor METHOD buildparta. product->add('PartX'). ENDMETHOD. "buildparta METHOD buildpartb. product->add('PartY'). ENDMETHOD. "buildpartb METHOD getresult. product = me->product. ENDMETHOD. "getresult ENDCLASS. "concretebuilder2 IMPLEMENTATION CLASS director DEFINITION. PUBLIC SECTION. METHODS: construct IMPORTING builder TYPE REF TO builder. ENDCLASS. "director DEFINITION CLASS director IMPLEMENTATION. METHOD construct. builder->buildparta( ). builder->buildpartb( ). ENDMETHOD. "construct ENDCLASS. "director IMPLEMENTATION CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-DATA: oa_creator_coll TYPE TABLE OF REF TO creator. CLASS-METHODS main. Version: 1.0 Side: 26

Project: Design Pattern ENDCLASS.

"mainapp DEFINITION

CLASS mainapp IMPLEMENTATION. METHOD main. DATA: director TYPE REF ,b1 TYPE REF ,b2 TYPE REF ,p1 TYPE REF ,p2 TYPE REF . FIELD-SYMBOLS TYPE ANY.

TO TO TO TO TO

director concretebuilder1 concretebuilder2 product product

CREATE OBJECT director. CREATE OBJECT b1. CALL METHOD director->construct( b1 ). p1 = b1->getresult( ). p1->show( ). CREATE OBJECT b2. CALL METHOD director->construct( b2 ). p2 = b2->getresult( ). p2->show( ). ENDMETHOD. ENDCLASS.

"main "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ). Output Product Parts PartA Partb Product Parts PartX PartY

2.1.2.7 Sample code In C# This real-world code demonstates the Builder pattern in which different vehicles are assembled in a step-by-step fashion. The Shop uses VehicleBuilders to construct a variety of Vehicles in a series of sequential steps. // Builder pattern -- Real World example using System; using System.Collections; namespace DoFactory.GangOfFour.Builder.RealWorld { // MainApp test application public class MainApp { public static void Main() { // Create shop with vehicle builders Shop shop = new Shop(); Version: 1.0 Side: 27

Project: Design Pattern VehicleBuilder b1 = new ScooterBuilder(); VehicleBuilder b2 = new CarBuilder(); VehicleBuilder b3 = new MotorCycleBuilder(); // Construct and display vehicles shop.Construct(b1); b1.Vehicle.Show(); shop.Construct(b2); b2.Vehicle.Show(); shop.Construct(b3); b3.Vehicle.Show(); // Wait for user Console.Read(); } } // "Director" class Shop { // Builder uses a complex series of steps public void Construct(VehicleBuilder vehicleBuilder) { vehicleBuilder.BuildFrame(); vehicleBuilder.BuildEngine(); vehicleBuilder.BuildWheels(); vehicleBuilder.BuildDoors(); } } // "Builder" abstract class VehicleBuilder { protected Vehicle vehicle; // Property public Vehicle Vehicle { get{ return vehicle; } } public public public public

abstract abstract abstract abstract

void void void void

BuildFrame(); BuildEngine(); BuildWheels(); BuildDoors();

} // "ConcreteBuilder1" class MotorCycleBuilder : VehicleBuilder { public override void BuildFrame() Version: 1.0 Side: 28

Project: Design Pattern { vehicle = new Vehicle("MotorCycle"); vehicle["frame"] = "MotorCycle Frame"; } public override void BuildEngine() { vehicle["engine"] = "500 cc"; } public override void BuildWheels() { vehicle["wheels"] = "2"; } public override void BuildDoors() { vehicle["doors"] = "0"; } } // "ConcreteBuilder2" class CarBuilder : VehicleBuilder { public override void BuildFrame() { vehicle = new Vehicle("Car"); vehicle["frame"] = "Car Frame"; } public override void BuildEngine() { vehicle["engine"] = "2500 cc"; } public override void BuildWheels() { vehicle["wheels"] = "4"; } public override void BuildDoors() { vehicle["doors"] = "4"; } } // "ConcreteBuilder3" class ScooterBuilder : VehicleBuilder { public override void BuildFrame() { vehicle = new Vehicle("Scooter"); vehicle["frame"] = "Scooter Frame"; } Version: 1.0 Side: 29

Project: Design Pattern

public override void BuildEngine() { vehicle["engine"] = "50 cc"; } public override void BuildWheels() { vehicle["wheels"] = "2"; } public override void BuildDoors() { vehicle["doors"] = "0"; } } // "Product" class Vehicle { private string type; private Hashtable parts = new Hashtable(); // Constructor public Vehicle(string type) { this.type = type; } // Indexer (i.e. smart array) public object this[string key] { get{ return parts[key]; } set{ parts[key] = value; } } public void Show() { Console.WriteLine("\n---------------------------"); Console.WriteLine("Vehicle Type: {0}", type); Console.WriteLine(" Frame : {0}", parts["frame"]); Console.WriteLine(" Engine : {0}", parts["engine"]); Console.WriteLine(" #Wheels: {0}", parts["wheels"]); Console.WriteLine(" #Doors : {0}", parts["doors"]); } } }

Output --------------------------Vehicle Type: Scooter Frame : Scooter Frame Engine : none #Wheels: 2 #Doors : 0 Version: 1.0 Side: 30

Project: Design Pattern

--------------------------Vehicle Type: Car Frame : Car Frame Engine : 2500 cc #Wheels: 4 #Doors : 4 --------------------------Vehicle Type: MotorCycle Frame : MotorCycle Frame Engine : 500 cc #Wheels: 2 #Doors : 0

2.1.2.8 Sample code In ABAP This real-world code demonstates the Builder pattern in which different vehicles are assembled in a step-by-step fashion. The Shop uses VehicleBuilders to construct a variety of Vehicles in a series of sequential steps. REPORT

zbuilder_realworld NO STANDARD PAGE HEADING LINE-SIZE 80.

CLASS vehicle DEFINITION. PUBLIC SECTION. TYPES: ty_key(30) TYPE c ,ty_part(30) TYPE c ,BEGIN OF ty_parts ,key TYPE ty_key ,part TYPE ty_part ,END OF ty_parts. METHODS: constructor IMPORTING vtype TYPE string ,add IMPORTING key TYPE ty_key part TYPE ty_part ,show. PRIVATE SECTION. DATA: parts TYPE HASHED TABLE OF ty_parts WITH UNIQUE KEY key ,vtype(30) TYPE c. ENDCLASS. "Vehicle DEFINITION CLASS vehicle IMPLEMENTATION. METHOD constructor. me->vtype = vtype. ENDMETHOD. "constructor METHOD add. DATA: buffer TYPE ty_parts. buffer-key = key. buffer-part = part. INSERT buffer INTO TABLE parts. ENDMETHOD. "add METHOD show. DATA: parts_line TYPE ty_parts. write: / '---------------------------------------------'. WRITE: / 'Vehicle Type:' , vtype. LOOP AT parts INTO parts_line. WRITE: / parts_line-key, parts_line-part. ENDLOOP. Version: 1.0 Side: 31

Project: Design Pattern ENDMETHOD. ENDCLASS.

"show "Vehicle IMPLEMENTATION

CLASS vehiclebuilder DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: constructor IMPORTING vtype TYPE string ,buildframe ABSTRACT ,buildengine ABSTRACT ,buildwheels ABSTRACT ,builddoors ABSTRACT ,getvehicle RETURNING value(vehicle) TYPE REF TO vehicle ,show. PROTECTED SECTION. DATA: vehicle TYPE REF TO vehicle. ENDCLASS. "builder DEFINITION CLASS vehiclebuilder IMPLEMENTATION. METHOD constructor. CREATE OBJECT vehicle EXPORTING vtype = vtype. ENDMETHOD. "constructor METHOD getvehicle. vehicle = me->vehicle. ENDMETHOD. METHOD show. vehicle->show( ). ENDMETHOD. ENDCLASS.

"vehicle

"show "vehiclebuilder IMPLEMENTATION

CLASS motorcyclebuilder DEFINITION INHERITING FROM vehiclebuilder. PUBLIC SECTION. METHODS: buildframe REDEFINITION ,buildengine REDEFINITION ,buildwheels REDEFINITION ,builddoors REDEFINITION . ENDCLASS. "Motorcycle DEFINITION CLASS motorcyclebuilder IMPLEMENTATION. METHOD buildframe. CREATE OBJECT vehicle EXPORTING vtype = 'MotorCycle'. vehicle->add( EXPORTING key = 'frame' part = 'Motorcycle Frame' ). ENDMETHOD. "buildparta METHOD buildengine. vehicle->add( EXPORTING key = 'engine' part = '500 cc' ). ENDMETHOD. "buildpartb METHOD buildwheels. vehicle->add( EXPORTING key = 'wheels' part = '2' ) . ENDMETHOD. "buildwheels METHOD builddoors. vehicle->add( EXPORTING key = 'doors' part = '0' ) . ENDMETHOD. "builddoors ENDCLASS. "Motorcycle IMPLEMENTATION CLASS carbuilder DEFINITION INHERITING FROM vehiclebuilder. PUBLIC SECTION. METHODS: buildframe REDEFINITION ,buildengine REDEFINITION ,buildwheels REDEFINITION Version: 1.0 Side: 32

Project: Design Pattern ,builddoors . ENDCLASS.

REDEFINITION "Carbuilder DEFINITION

CLASS carbuilder IMPLEMENTATION. METHOD buildframe. CREATE OBJECT vehicle EXPORTING vtype = 'Car'. vehicle->add( EXPORTING key = 'frame' part = 'Car Frame' ). ENDMETHOD. "buildparta METHOD buildengine. vehicle->add( EXPORTING key = 'engine' part = '2500 cc' ). ENDMETHOD. "buildpartb METHOD buildwheels. vehicle->add( EXPORTING key = 'wheels' part = '4' ) . ENDMETHOD. "buildwheels METHOD builddoors. vehicle->add( EXPORTING key = 'doors' part = '4' ) . ENDMETHOD. "builddoors ENDCLASS.

"Carbuilder IMPLEMENTATION

CLASS scooterbuilder DEFINITION INHERITING FROM vehiclebuilder. PUBLIC SECTION. METHODS: buildframe REDEFINITION ,buildengine REDEFINITION ,buildwheels REDEFINITION ,builddoors REDEFINITION . ENDCLASS. "Scooterbuilder DEFINITION CLASS scooterbuilder IMPLEMENTATION. METHOD buildframe. CREATE OBJECT vehicle EXPORTING vtype = 'Scooter'. vehicle->add( EXPORTING key = 'frame' part = 'Scooter Frame' ). ENDMETHOD. "buildparta METHOD buildengine. vehicle->add( EXPORTING key = 'engine' part = '50 cc' ). ENDMETHOD. "buildpartb METHOD buildwheels. vehicle->add( EXPORTING key = 'wheels' part = '2' ) . ENDMETHOD. "buildwheels METHOD builddoors. vehicle->add( EXPORTING key = 'doors' part = '0' ) . ENDMETHOD. "builddoors ENDCLASS.

"Carbuilder IMPLEMENTATION

CLASS shop DEFINITION. PUBLIC SECTION. METHODS: construct IMPORTING vehiclebuilder TYPE REF TO vehiclebuilder. ENDCLASS. "shop DEFINITION CLASS shop IMPLEMENTATION. METHOD construct. vehiclebuilder->buildframe( ). vehiclebuilder->buildengine( ). Version: 1.0 Side: 33

Project: Design Pattern vehiclebuilder->buildwheels( ). vehiclebuilder->builddoors( ). ENDMETHOD. "construct ENDCLASS. "shop IMPLEMENTATION CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-DATA: oa_creator_coll TYPE TABLE OF REF TO creator. CLASS-METHODS main. ENDCLASS. "mainapp DEFINITION CLASS mainapp IMPLEMENTATION. METHOD main. DATA: shop TYPE REF TO shop ,b1 TYPE REF TO scooterbuilder ,b2 TYPE REF TO carbuilder ,b3 TYPE REF TO motorcyclebuilder . * Create shop with vehiclle builders CREATE OBJECT shop. CREATE OBJECT b1 EXPORTING vtype = 'Scooter'. CREATE OBJECT b2 EXPORTING vtype = 'Car'. CREATE OBJECT b3 EXPORTING vtype = 'MotorCycle'. *

Construct and display vehicles CALL METHOD shop->construct( b1 ). b1->show( ). CALL METHOD shop->construct( b2 ). b2->show( ). CALL METHOD shop->construct( b3 ). b3->show( ).

ENDMETHOD. ENDCLASS.

"main "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ). Vehicle Type: Scooter frame engine wheels doors

Scooter Frame 50 cc 2 0

Vehicle Type: Car frame engine wheels doors

Car Frame 2500 cc 4 4

Vehicle Type: MotorCycle frame engine wheels doors

Motorcycle Frame 500 cc 2 0

2.1.3 Factory Method Creates an instance of several derived classes

2.1.3.1 Definition Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses. Version: 1.0 Side: 34

Project: Design Pattern

2.1.3.2 UML class diagram

The product is a generelization of the concrete product, like the creator is a generelization of the spacialized concretecreator. The ConcreteCreator have dependency off Product Class

2.1.3.3 Participants The classes and/or objects participating in this pattern are: o Product (Page) o defines the interface of objects the factory method creates o ConcreteProduct (SkillsPage, EducationPage, ExperiencePage) o implements the Product interface o Creator (Document) o declares the factory method, which returns an object of type Product. Creator may also define a default implementation of the factory method that returns a default ConcreteProduct object. may call the factory method to create a Product object. o ConcreteCreator (Report, Resume) o overrides the factory method to return an instance of a ConcreteProduct.

2.1.3.4 Sample code In C# This structural code demonstrates the Factory method offering great flexibility in creating different objects. The Abstract class may provide a default object, but each subclass can instantiate an extended version of the object. // Factory Method pattern -- Structural example using System; using System.Collections; namespace DoFactory.GangOfFour.Factory.Structural { // MainApp test application

Version: 1.0 Side: 35

Project: Design Pattern

class MainApp { static void Main() { // An array of creators Creator[] creators = new Creator[2]; creators[0] = new ConcreteCreatorA(); creators[1] = new ConcreteCreatorB(); // Iterate over creators and create products foreach(Creator creator in creators) { Product product = creator.FactoryMethod(); Console.WriteLine("Created {0}", product.GetType().Name); } // Wait for user Console.Read(); } } // "Product" abstract class Product { } // "ConcreteProductA" class ConcreteProductA : Product { } // "ConcreteProductB" class ConcreteProductB : Product { } // "Creator" abstract class Creator { public abstract Product FactoryMethod(); } // "ConcreteCreator" class ConcreteCreatorA : Creator { public override Product FactoryMethod() { return new ConcreteProductA(); } Version: 1.0 Side: 36

Project: Design Pattern } // "ConcreteCreator" class ConcreteCreatorB : Creator { public override Product FactoryMethod() { return new ConcreteProductB(); } } }

Output Created ConcreteProductA Created ConcreteProductB

This real-world code demonstrates the Factory method offering flexibility in creating different documents. The derived Document classes Report and Resume instantiate extended versions of the Document class. Here, the Factory Method is called in the constructor of the Document base class. // Factory Method pattern -- Real World example using System; using System.Collections; namespace DoFactory.GangOfFour.Factory.RealWorld { // MainApp test application class MainApp { static void Main() { // Note: constructors call Factory Method Document[] documents = new Document[2]; documents[0] = new Resume(); documents[1] = new Report(); // Display document pages foreach (Document document in documents) { Console.WriteLine("\n" + document.GetType().Name+ "--"); foreach (Page page in document.Pages) { Console.WriteLine(" " + page.GetType().Name); } } // Wait for user Console.Read(); } } Version: 1.0 Side: 37

Project: Design Pattern

// "Product" abstract class Page { } // "ConcreteProduct" class SkillsPage : Page { } // "ConcreteProduct" class EducationPage : Page { } // "ConcreteProduct" class ExperiencePage : Page { } // "ConcreteProduct" class IntroductionPage : Page { } // "ConcreteProduct" class ResultsPage : Page { } // "ConcreteProduct" class ConclusionPage : Page { } // "ConcreteProduct" class SummaryPage : Page { } // "ConcreteProduct" class BibliographyPage : Page { } // "Creator" Version: 1.0 Side: 38

Project: Design Pattern

abstract class Document { private ArrayList pages = new ArrayList(); // Constructor calls abstract Factory method public Document() { this.CreatePages(); } public ArrayList Pages { get{ return pages; } } // Factory Method public abstract void CreatePages(); } // "ConcreteCreator" class Resume : Document { // Factory Method implementation public override void CreatePages() { Pages.Add(new SkillsPage()); Pages.Add(new EducationPage()); Pages.Add(new ExperiencePage()); } } // "ConcreteCreator" class Report : Document { // Factory Method implementation public override void CreatePages() { Pages.Add(new IntroductionPage()); Pages.Add(new ResultsPage()); Pages.Add(new ConclusionPage()); Pages.Add(new SummaryPage()); Pages.Add(new BibliographyPage()); } } }

Output Resume ------SkillsPage EducationPage ExperiencePage Report ------IntroductionPage Version: 1.0 Side: 39

Project: Design Pattern ResultsPage ConclusionPage SummaryPage BibliographyPage

2.1.3.5 Sample code in ABAP This structural code demonstrates the Factory method offering great flexibility in creating different objects. The Abstract class may provide a default object, but each subclass can instantiate an extended version of the object. In ABAP Classes you can’t get the classname with build in functions.Often you don’t need The classname, but sometimes when you process collection of classes you need to do dependent class processes, and therefore you need to know which class you are working with. Using a standard SAP class we are able to get the class name. In the examples I have build this code into a macro for easy use: * Macro Definition DEFINE ?get_class_name. &2 = cl_abap_classdescr=>get_class_name( &1 ). find regex 'CLASS=' in &2 match offset moff match length mlen. slen = moff + mlen. shift &2 by slen places left. END-OF-DEFINITION. * Call macro with parameter ?get_class_name product class_name.

REPORT zfactory_structural NO STANDARD PAGE HEADING LINE-SIZE 80. CLASS product DEFINITION DEFERRED. CLASS concreteproducta DEFINITION DEFERRED. CLASS concreteproductb DEFINITION DEFERRED . CLASS CLASS CLASS CLASS

creator concretecreatora concretecreatorb cl_abap_typedescr

DEFINITION DEFINITION DEFINITION DEFINITION

DEFERRED. DEFERRED. DEFERRED. LOAD.

data: moff type i ,slen type i ,mlen type i. DEFINE ?get_class_name. &2 = cl_abap_classdescr=>get_class_name( &1 ). find regex 'CLASS=' in &2 match offset moff match length mlen. slen = moff + mlen. shift &2 by slen places left. END-OF-DEFINITION. CLASS product DEFINITION ABSTRACT. ENDCLASS. "product DEFINITION

CLASS concreteproducta DEFINITION INHERITING FROM product. ENDCLASS. "concreteproducta DEFINITION CLASS concreteproductb DEFINITION INHERITING FROM product. ENDCLASS. "concreteproductB DEFINITION Version: 1.0 Side: 40

Project: Design Pattern

CLASS creator DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: factorymethod ABSTRACT RETURNING value(product) TYPE REF TO product. ENDCLASS. "product DEFINITION CLASS concretecreatora DEFINITION INHERITING FROM creator. PUBLIC SECTION. METHODS: factorymethod REDEFINITION. ENDCLASS. "concretecreatora DEFINITION CLASS concretecreatora IMPLEMENTATION. METHOD factorymethod. CREATE OBJECT product TYPE concreteproducta. ENDMETHOD. "factoryproduct ENDCLASS. "concretecreatora IMPLEMENTATION CLASS concretecreatorb DEFINITION INHERITING FROM creator. PUBLIC SECTION. METHODS: factorymethod REDEFINITION. ENDCLASS. "concretecreatorb DEFINITION CLASS concretecreatorb IMPLEMENTATION. METHOD factorymethod. CREATE OBJECT product TYPE concreteproductb. ENDMETHOD. "factoryproduct ENDCLASS. "concretecreatorb IMPLEMENTATION CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-DATA: oa_creator_coll TYPE TABLE OF REF TO creator. CLASS-METHODS main. ENDCLASS. "mainapp DEFINITION CLASS mainapp IMPLEMENTATION. METHOD main. DATA: creator TYPE REF TO creator ,concretecreatora TYPE REF TO concretecreatora ,concretecreatorb TYPE REF TO concretecreatorb ,product TYPE REF TO product ,class_name TYPE abap_abstypename . FIELD-SYMBOLS TYPE ANY. CREATE OBJECT concretecreatora. APPEND concretecreatora TO oa_creator_coll. CREATE OBJECT concretecreatorb. APPEND concretecreatorb TO oa_creator_coll. LOOP AT oa_creator_coll ASSIGNING . ?get_class_name class_name. CASE class_name. WHEN 'CONCRETECREATORA'. WRITE: / 'ConcreteCreatorA Creates Product A'. WHEN 'CONCRETECREATORB'. WRITE: / 'ConcreteCreatorB Creates Product B'. ENDCASE. creator = . product = creator->factorymethod( ). ?get_class_name product class_name. WRITE: / 'Product =',class_name. ENDLOOP. Version: 1.0 Side: 41

Project: Design Pattern

ENDMETHOD. ENDCLASS.

"main "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ).

Output ConcreteCreatorA Creates ProductA Product = CONCRETEPRODUCTA ConcreteCreatorB Creates ProductB Product = CONCRETEPRODUCTB

2.1.3.6 Sample code in ABAP This structural code demonstrates the Factory method offering great flexibility in creating different objects. In this example the Abstract class have been replaced by using interfaces. Each subclass must implement the interface and each subclass can instantiate their own class versiob decoupled from a common parent class as long it implement the same interface. REPORT zfactory_structural NO STANDARD PAGE HEADING LINE-SIZE 80. CLASS cl_abap_typedescr DEFINITION LOAD. DATA: moff TYPE i ,slen TYPE i ,mlen TYPE i.

DEFINE ?get_class_name. &2 = cl_abap_classdescr=>get_class_name( &1 ). find regex 'CLASS=' in &2 match offset moff match length mlen. slen = moff + mlen. shift &2 by slen places left. END-OF-DEFINITION. INTERFACE product. TYPES ty_productname(30) TYPE c. DATA: name TYPE ty_productname. METHODS: get_name RETURNING value(name) TYPE ty_productname. ENDINTERFACE. CLASS concreteproducta DEFINITION. PUBLIC SECTION. INTERFACES: product. ENDCLASS. "concreteproducta DEFINITION CLASS concreteproducta IMPLEMENTATION. METHOD product~get_name. name = 'ConcreteProductA'. ENDMETHOD. "product~getname ENDCLASS. "concreteproducta IMPLEMENTATION CLASS concreteproductb DEFINITION. Version: 1.0 Side: 42

Project: Design Pattern PUBLIC SECTION. INTERFACES: product. ENDCLASS.

"concreteproductB DEFINITION

CLASS concreteproductb IMPLEMENTATION. METHOD product~get_name. name = 'ConCreteProductB'. ENDMETHOD. "product~getname ENDCLASS. "concreteproductB IMPLEMENTATION INTERFACE creator. METHODS: factorymethod RETURNING value(product) TYPE REF TO product. ENDINTERFACE. CLASS concretecreatora DEFINITION. PUBLIC SECTION. INTERFACES: creator. ENDCLASS. "concretecreatora DEFINITION CLASS concretecreatora IMPLEMENTATION. METHOD creator~factorymethod. CREATE OBJECT product TYPE concreteproducta. ENDMETHOD. "factoryproduct ENDCLASS. "concretecreatora IMPLEMENTATION CLASS concretecreatorb DEFINITION. PUBLIC SECTION. INTERFACES: creator. ENDCLASS. "concretecreatorb DEFINITION CLASS concretecreatorb IMPLEMENTATION. METHOD creator~factorymethod. CREATE OBJECT product TYPE concreteproductb. ENDMETHOD. "factoryproduct ENDCLASS. "concretecreatorb IMPLEMENTATION CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-DATA: oa_creator_coll TYPE TABLE OF REF TO creator. CLASS-METHODS main. ENDCLASS. "mainapp DEFINITION CLASS mainapp IMPLEMENTATION. METHOD main. data: concretecreatora TYPE ,concretecreatorb TYPE ,product TYPE ,product_name(30) type ,class_name TYPE . FIELD-SYMBOLS TYPE REF

REF TO concretecreatora REF TO concretecreatorb REF TO product c abap_abstypename TO creator.

CREATE OBJECT concretecreatora. APPEND concretecreatora TO oa_creator_coll. CREATE OBJECT concretecreatorb. APPEND concretecreatorb TO oa_creator_coll. LOOP AT oa_creator_coll ASSIGNING . *

Call macro to find out which Creator and Product are active ?get_class_name class_name.

Version: 1.0 Side: 43

Project: Design Pattern CASE class_name. WHEN 'CONCRETECREATORA'. WRITE: / 'ConcreteCreatorA Creates Product A'. WHEN 'CONCRETECREATORB'. WRITE: / 'ConcreteCreatorB Creates Product B'. ENDCASE. product = ->factorymethod( ) . ?get_class_name product class_name. product_name = product->get_name( ). WRITE: / 'Class= ', class_name,'Product =',product_name. ENDLOOP. ENDMETHOD. ENDCLASS.

"main "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ).

Output ConcreteCreatorA Creates ProductA Class = CONCRETEPRODUCTA Product = ConcreteProductA ConcreteCreatorB Creates ProductB Class = CONCRETEPRODUCTB Product = ConcreteProductB

2.1.3.7 Sample code in ABAP This real-world code demonstrates the Factory method offering flexibility in creating different documents. The derived Document classes Report and Resume instantiate extended versions of the Document class. Here, the Factory Method is called in the constructor of the Document derived class, in ABAP you cannot call an abstract method from the abstract base class constructor. REPORT zfactory_structural NO STANDARD PAGE HEADING LINE-SIZE 80. CLASS cl_abap_typedescr DEFINITION LOAD. DATA: moff TYPE i ,slen TYPE i ,mlen TYPE i. DEFINE ?get_class_name. &2 = cl_abap_classdescr=>get_class_name( &1 ). find regex 'CLASS=' in &2 match offset moff match length mlen. slen = moff + mlen. shift &2 by slen places left. END-OF-DEFINITION. CLASS page DEFINITION ABSTRACT. ENDCLASS. "page DEFINITION CLASS skillspage DEFINITION INHERITING FROM page. ENDCLASS. "skillspage DEFINITION CLASS educationpage DEFINITION INHERITING FROM page. Version: 1.0 Side: 44

Project: Design Pattern ENDCLASS.

"educationpage DEFINITION

CLASS experiencepage DEFINITION INHERITING FROM page. ENDCLASS. "experiencepage DEFINITION CLASS introductionpage DEFINITION INHERITING FROM page. ENDCLASS. "introductionpage DEFINITION CLASS resultspage DEFINITION INHERITING FROM page. ENDCLASS. "resultspage DEFINITION CLASS conclusionpage DEFINITION INHERITING FROM page. ENDCLASS. "conclusionpage DEFINITION CLASS summarypage DEFINITION INHERITING FROM page. ENDCLASS. "summarypage DEFINITION CLASS bibliographypage DEFINITION INHERITING FROM page. ENDCLASS. "bibliographypage DEFINITION CLASS document DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: createpages ABSTRACT ,pages EXPORTING pages TYPE ANY TABLE . PROTECTED SECTION. DATA: oa_pages_coll TYPE TABLE OF REF TO page. ENDCLASS. "document DEFINITION CLASS document IMPLEMENTATION. METHOD pages. pages[] = oa_pages_coll[]. ENDMETHOD. ENDCLASS.

"pages

"document IMPLEMENTATION

CLASS resume DEFINITION INHERITING FROM document. PUBLIC SECTION. METHODS: constructor ,createpages REDEFINITION. ENDCLASS. "resume DEFINITION CLASS resume IMPLEMENTATION. METHOD constructor. super->constructor( ). CALL METHOD me->createpages. ENDMETHOD. "constructor METHOD createpages. DATA: page TYPE REF TO page. CREATE OBJECT page TYPE skillspage. APPEND page TO oa_pages_coll. CREATE OBJECT page TYPE educationpage. APPEND page TO oa_pages_coll. CREATE OBJECT page TYPE experiencepage. APPEND page TO oa_pages_coll. ENDMETHOD. ENDCLASS.

Version: 1.0 Side: 45

"createpages "resume IMPLEMENTATION

Project: Design Pattern CLASS report DEFINITION INHERITING FROM document. PUBLIC SECTION. METHODS: constructor ,createpages REDEFINITION. ENDCLASS. "report DEFINITION CLASS report IMPLEMENTATION. METHOD constructor. super->constructor( ). CALL METHOD me->createpages. ENDMETHOD. "constructor METHOD createpages. DATA: page TYPE REF TO page. CREATE OBJECT page TYPE introductionpage. APPEND page TO oa_pages_coll. CREATE OBJECT page TYPE resultspage. APPEND page TO oa_pages_coll. CREATE OBJECT page TYPE conclusionpage. APPEND page TO oa_pages_coll. CREATE OBJECT page TYPE summarypage. APPEND page TO oa_pages_coll. CREATE OBJECT page TYPE bibliographypage. APPEND page TO oa_pages_coll. ENDMETHOD. ENDCLASS.

"createpages "report IMPLEMENTATION

CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-DATA: oa_document_coll TYPE TABLE OF REF TO document. CLASS-METHODS main. ENDCLASS. "mainapp DEFINITION CLASS mainapp IMPLEMENTATION. METHOD main. DATA: document TYPE REF TO document ,resume TYPE REF TO resume ,report TYPE REF TO report ,page TYPE REF TO page ,class_name TYPE abap_abstypename ,pages_coll TYPE TABLE OF REF TO page. . FIELD-SYMBOLS: TYPE REF TO document , TYPE REF TO page. CREATE OBJECT resume. APPEND resume TO oa_document_coll. CREATE OBJECT report. APPEND report TO oa_document_coll. * *

*

Loop at all documents LOOP AT oa_document_coll ASSIGNING . Call macro to find out which Creator and Product are active ?get_class_name class_name. CASE class_name. WHEN 'RESUME'. WRITE: / 'Resume contains following pages:', / sy-uline. CALL METHOD ->pages( IMPORTING pages = pages_coll ). Loop at all pages in document Resume

Version: 1.0 Side: 46

Project: Design Pattern

*

LOOP AT pages_coll ASSIGNING . ?get_class_name class_name. WRITE: / class_name. ENDLOOP. WHEN 'REPORT'. WRITE: / 'Report contains following pages:', / sy-uline. CALL METHOD ->pages( IMPORTING pages = pages_coll ). Loop at all pages in document Resume LOOP AT pages_coll ASSIGNING . ?get_class_name class_name. WRITE: / class_name. ENDLOOP. ENDCASE. ENDLOOP.

ENDMETHOD. ENDCLASS.

"main "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ). Output: Resume contains following pages: SKILLSPAGE EDUCATIONPAGE EXPERIENCEPAGE Report contains following pages: INTRODUCTIONPAGE RESULTSPAGE CONCLUSIONPAGE SUMMARYPAGE BIBLIOGRAPHYPAGE

2.1.4 Prototype A fully initialized instance to be copied or cloned

2.1.4.1 Definition Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype.

2.1.4.2 Used for Prototype pattern is usally used to create objects when the process of object creation is time consuming when done from scratch. In this case an existing object is used as an prototype and similar objects are constructed using this prototype (without using constructor)

Version: 1.0 Side: 47

Project: Design Pattern

2.1.4.3 UML class diagram

2.1.4.4 Participants The classes and/or objects participating in this pattern are: o Prototype (ColorPrototype) o declares an interface for cloning itself o ConcretePrototype (Color) o implements an operation for cloning itself o Client (ColorManager) o creates a new object by asking a prototype to clone itself

2.1.4.5 Sample code In C# This structural code demonstrates the Prototype pattern in which new objects are created by copying pre-existing objects (prototypes) of the same class. // Prototype pattern -- Structural example using System; namespace DoFactory.GangOfFour.Prototype.Structural { // MainApp test application class MainApp { static void Main() { // Create two instances and clone each ConcretePrototype1 p1 = new ConcretePrototype1("I"); ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone(); Console.WriteLine ("Cloned: {0}", c1.Id); Version: 1.0 Side: 48

Project: Design Pattern

ConcretePrototype2 p2 = new ConcretePrototype2("II"); ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone(); Console.WriteLine ("Cloned: {0}", c2.Id); // Wait for user Console.Read(); } } // "Prototype" abstract class Prototype { private string id; // Constructor public Prototype(string id) { this.id = id; } // Property public string Id { get{ return id; } } public abstract Prototype Clone(); } // "ConcretePrototype1" class ConcretePrototype1 : Prototype { // Constructor public ConcretePrototype1(string id) : base(id) { } public override Prototype Clone() { // Shallow copy return (Prototype)this.MemberwiseClone(); } } // "ConcretePrototype2" class ConcretePrototype2 : Prototype { // Constructor public ConcretePrototype2(string id) : base(id) { }

Version: 1.0 Side: 49

Project: Design Pattern public override Prototype Clone() { // Shallow copy return (Prototype)this.MemberwiseClone(); } } }

Output Cloned: I Cloned: II

2.1.4.6 Sample code In ABAP This structural code demonstrates the Prototype pattern in which new objects are created by copying pre-existing objects (prototypes) of the same class. We uses UP CASTING where the code can’t be checked before runtime. *&---------------------------------------------------------------------* *& Report ZPROTOTYPE_STRUCTURAL *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT

zprototype_structural.

*----------------------------------------------------------------------* * CLASS prototype DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS prototype DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: constructor IMPORTING id TYPE string ,get_id RETURNING value(id) TYPE string ,clone ABSTRACT RETURNING value(prototype) TYPE REF TO prototype . PRIVATE SECTION. DATA: id TYPE string. ENDCLASS. "prototype DEFINITION *----------------------------------------------------------------------* * CLASS prototype IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS prototype IMPLEMENTATION. METHOD constructor. me->id = id. ENDMETHOD. "constructor METHOD get_id. id = me->id. Version: 1.0 Side: 50

Project: Design Pattern ENDMETHOD. ENDCLASS.

"get_id "prototype IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS concreteprototype1 DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concreteprototype1 DEFINITION INHERITING FROM prototype. PUBLIC SECTION. METHODS: clone REDEFINITION. ENDCLASS. "concreteprototype1 DEFINITION *----------------------------------------------------------------------* * CLASS concreteprototype1 IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concreteprototype1 IMPLEMENTATION. METHOD clone. prototype = me. ENDMETHOD. "clone ENDCLASS. "concreteprototype1 IMPLEMENTATION *----------------------------------------------------------------------* * CLASS concreteprototype2 DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concreteprototype2 DEFINITION INHERITING FROM prototype. PUBLIC SECTION. METHODS: clone REDEFINITION. ENDCLASS. "concreteprototype2 DEFINITION *----------------------------------------------------------------------* * CLASS concreteprototype2 IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concreteprototype2 IMPLEMENTATION. METHOD clone. prototype = me. ENDMETHOD. "clone ENDCLASS. "concreteprototype2 IMPLEMENTATION *----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------*

Version: 1.0 Side: 51

Project: Design Pattern * *----------------------------------------------------------------------* CLASS mainapp IMPLEMENTATION. METHOD main. data: p1 type REF TO concreteprototype1 ,c1 type REF TO concreteprototype1 ,p2 TYPe REF TO concreteprototype2 ,c2 type REF TO concreteprototype2 ,id type string . field-SYMBOLS type REF TO prototype. *

Create two instances and clone each create object p1 exporting id = 'I'. c1 ?= p1->clone( ). id = c1->get_id( ). write: / 'Cloned: {0}', id.

* *

Down Casting uses assign operator ?= as it can not be checked before runtine create object p2 exporting id = 'II'. c2 ?= p2->clone( ). id = c2->get_id( ). write: / 'Cloned: {0}', id.

ENDMETHOD. ENDCLASS.

"endmethod "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ). Output Program ZPROTOTYPE_STRUCTURAL Cloned: {0} I Cloned: {0} II

2.1.4.7 Sample code In C# This real-world code demonstrates the Prototype pattern in which new Color objects are created by copying pre-existing, user-defined Colors of the same type. // Prototype pattern -- Real World example using System; using System.Collections; namespace DoFactory.GangOfFour.Prototype.RealWorld { // MainApp test application class MainApp { static void Main() Version: 1.0 Side: 52

Project: Design Pattern { ColorManager colormanager = new ColorManager(); // Initialize with standard colors colormanager["red" ] = new Color(255, 0, 0); colormanager["green"] = new Color( 0, 255, 0); colormanager["blue" ] = new Color( 0, 0, 255); // User adds personalized colors colormanager["angry"] = new Color(255, 54, 0); colormanager["peace"] = new Color(128, 211, 128); colormanager["flame"] = new Color(211, 34, 20); Color color; // User uses selected colors string name = "red"; color = colormanager[name].Clone() as Color; name = "peace"; color = colormanager[name].Clone() as Color; name = "flame"; color = colormanager[name].Clone() as Color; // Wait for user Console.Read(); } } // "Prototype" abstract class ColorPrototype { public abstract ColorPrototype Clone(); } // "ConcretePrototype" class Color : { private int private int private int

ColorPrototype red; green; blue;

// Constructor public Color(int red, int green, int blue) { this.red = red; this.green = green; this.blue = blue; } // Create a shallow copy public override ColorPrototype Clone() { Version: 1.0 Side: 53

Project: Design Pattern Console.WriteLine( "Cloning color RGB: {0,3},{1,3},{2,3}", red, green, blue); return this.MemberwiseClone() as ColorPrototype; } } // Prototype manager class ColorManager { Hashtable colors = new Hashtable(); // Indexer public ColorPrototype this[string name] { get { return colors[name] as ColorPrototype; } set { colors.Add(name, value); } } } }

Output Cloning color RGB: 255, 0, 0 Cloning color RGB: 128,211,128 Cloning color RGB: 211, 34, 20

2.1.4.8 Sample code In ABAP This real-world code demonstrates the Prototype pattern in which new Color objects are created by copying pre-existing, user-defined Colors of the same type.

In the clone method this example does not create a new instance, but merely returns actual instans and thereby you have two variables pointing to the same instance. A true clone would create a new instance copy all the instance attributes from actual instanceto the new clone and thereby you would have a real clone that can live it’s own life. *&---------------------------------------------------------------------* *& Report ZPROTOTYPE_REALWORLD *& *&---------------------------------------------------------------------* *&

Version: 1.0 Side: 54

Project: Design Pattern *& *&---------------------------------------------------------------------* REPORT

zprototype_realworld.

*----------------------------------------------------------------------* * CLASS colorprototype DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS colorprototype DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: clone ABSTRACT RETURNING value(colorprototype) TYPE REF TO colorprototype. ENDCLASS. "prototype DEFINITION

*----------------------------------------------------------------------* * CLASS color DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS color DEFINITION INHERITING FROM colorprototype. PUBLIC SECTION. METHODS: constructor IMPORTING red TYPE i green TYPE i blue TYPE i ,clone REDEFINITION. PROTECTED SECTION. DATA: xred TYPE i ,xgreen TYPE i ,xblue TYPE i. ENDCLASS. "concreteprototype1 DEFINITION *----------------------------------------------------------------------* * CLASS color IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS color IMPLEMENTATION. METHOD constructor. super->constructor( ). xred = red. xgreen = green. xblue = blue. ENDMETHOD. "constructor METHOD clone. WRITE: / 'Cloning color RGB: {0,3},{1,3},{2,3}', me->xred, me->xgreen, me->xblue. colorprototype = me. ENDMETHOD. "clone ENDCLASS. "concreteprototype1 IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS colormanager DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS colormanager DEFINITION. PUBLIC SECTION. TYPES: BEGIN OF ty_colors ,name TYPE string ,color TYPE REF TO colorprototype ,END OF ty_colors. Version: 1.0 Side: 55

Project: Design Pattern

DATA: colors TYPE HASHED TABLE OF ty_colors WITH UNIQUE KEY name. METHODS: get IMPORTING name TYPE string RETURNING value(Pcolors) TYPE REF TO colorprototype ,set IMPORTING name TYPE string pcolor TYPE REF TO colorprototype. . ENDCLASS. "colormanager DEFINITION *----------------------------------------------------------------------* * CLASS colormanager IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS colormanager IMPLEMENTATION. METHOD get. DATA buffer TYPE ty_colors. FIELD-SYMBOLS TYPE ty_colors. READ TABLE me->colors WITH TABLE KEY name = name INTO buffer. Pcolors = buffer-color. ENDMETHOD. "get method set. DATA buffer TYPE ty_colors. buffer-name = name. buffer-color = pcolor. INSERT buffer INTO TABLE colors. endmethod. ENDCLASS.

"colormanager IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp IMPLEMENTATION. METHOD main. data: colormanager type REF TO colormanager ,!color type REF TO color ,name type string . *

Create the color manager create OBJECT colormanager. create OBJECT !color EXPORTING red = 255 green = 0 blue = 0 . colormanager->set( EXPORTING name = 'red' pcolor = !color ). create OBJECT !color EXPORTING red = 0 green = 255 blue = 0 . colormanager->set( EXPORTING name = 'green' pcolor = !color ). create OBJECT !color EXPORTING red = 0 green = 0 blue = 255 . colormanager->set( EXPORTING name = 'blue' pcolor = !color ).

Version: 1.0 Side: 56

Project: Design Pattern

create OBJECT !color EXPORTING red = 255 green = 54 blue = 0 . colormanager->set( EXPORTING name = 'angry' pcolor = !color ). create OBJECT !color EXPORTING red = 128 green = 211 blue = 128 . colormanager->set( EXPORTING name = 'peace' pcolor = !color ). create OBJECT !color EXPORTING red = 211 green = 34 blue = 20 . colormanager->set( EXPORTING name = 'flame' pcolor = !color ). name = 'red'. !color ?= colormanager->get( name ). !color ?= !color->clone( ).

"!color is a colorprototype "!color is a color

name = 'peace'. !color ?= colormanager->get( name ). !color ?= !color->clone( ).

"!color is a colorprototype "!color is a color

name = 'flame'. !color ?= colormanager->get( name ). !color ?= !color->clone( ).

"!color is a colorprototype "!color is a color

ENDMETHOD. ENDCLASS.

"endmethod "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ).

Output: Program ZPROTOTYPE_STRUCTURAL Cloning color RGB: {0,3},{1,3},{2,3} Cloning color RGB: {0,3},{1,3},{2,3} Cloning color RGB: {0,3},{1,3},{2,3}

255 128 211

0 211 34

0 128 20

2.1.5 Singleton A class of which only a single instance can exist

2.1.5.1 Definition Ensure a class has only one instance and provide a global point of access to it. In software engineering, the singleton pattern is a design pattern that is used to restrict instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. Sometimes it is generalized to systems that operate more efficiently when only one or a few objects exist. It is also considered an anti-pattern since it is often used as a euphemism for global variable.

2.1.5.2 Common Use •

Abstract Factory, Builder, and Prototype patterns can use Singletons in their implementation.

Version: 1.0 Side: 57

Project: Design Pattern • • •





Facade objects are often Singletons because only one Facade object is required. State objects are often Singletons. Singletons are often preferred to global variables because: o They don't pollute the global namespace (or, in languages with namespaces, their containing namespace) with unnecessary variables. o They permit lazy allocation and initialization, where global variables in many languages will always consume resources. Singletons behave differently depending on the lifetime of the virtual machine. While a software development kit may start a new virtual machine for every run which results in a new instance of the singleton being created, calls to a singleton e.g. within the virtual machine of an application server behave differently. There the virtual machine remains alive, therefore the instance of the singleton remains as well. Running the code again therefore can retrieve the "old" instance of the singleton which then may be contaminated with values in local fields which are the result of the first run. Main application in abap, if implemented as OOP style the mainapplication class uses local singleton to assure that the program is not run several times.

2.1.5.3 Implementation The singleton pattern is implemented by creating a class with a method that creates a new instance of the class if one does not exist. If an instance already exists, it simply returns a reference to that object. To make sure that the object cannot be instantiated any other way, the constructor is made either private or protected. Note the distinction between a simple static instance of a class and a singleton: although a singleton can be implemented as a static instance, it can also be lazily constructed, requiring no memory or resources until needed. Another notable difference is that static member classes cannot implement an interface, unless that interface is simply a marker. So if the class has to realize a contract expressed by an interface, you really have to make it a singleton. The singleton pattern must be carefully constructed in multi-threaded applications. If two threads are to execute the creation method at the same time when a singleton does not yet exist, they both must check for an instance of the singleton and then only one should create the new one. If the programming language has concurrent processing capabilities the method should be constructed to execute as a mutually exclusive operation. The classic solution to this problem is to use mutual exclusion on the class that indicates that the object is being instantiated.

Version: 1.0 Side: 58

Project: Design Pattern The singleton are not useful for inheritage, as all inheritated classes only have one common instance and because the superclass only have one attribute with the created instance. Singleton classes should therefore be marked as FINAL. Another reason for bad inheritance, is if the singleton superclass tries to create instances, as the superclass does not know the local class, therefore we are getting type casting problems. You can however use singleton in inheritage if your own class has been registered in the dictionary {SE24} and if your class has been registered as a friend to the singleton superclass. Your singleton should then have an collection af classes of which only one instance per class are allowed. But then you must use dynamic creation and thereby you need to export the classname as a parameter to get_instance.

2.1.5.4 UML class diagram

2.1.5.5 Participants The classes and/or objects participating in this pattern are: o Singleton (LoadBalancer) o defines an Instance operation that lets clients access its unique instance. Instance is a class operation responsible for creating and maintaining its own unique instance.

2.1.5.6 Sample code In C# This structural code demonstrates the Singleton pattern which assures only a single instance (the singleton) of the class can be created. // Singleton pattern -- Structural example using System; namespace DoFactory.GangOfFour.Singleton.Structural { // MainApp test application class MainApp { static void Main() Version: 1.0 Side: 59

Project: Design Pattern { // Constructor is protected -- cannot use new Singleton s1 = Singleton.Instance(); Singleton s2 = Singleton.Instance(); if (s1 == s2) { Console.WriteLine("Objects are the same instance"); } // Wait for user Console.Read(); } } // "Singleton" class Singleton { private static Singleton instance; // Note: Constructor is 'protected' protected Singleton() { } public static Singleton Instance() { // Use 'Lazy initialization' if (instance == null) { instance = new Singleton(); } return instance; } } }

Output ÎObjects are the same instance

2.1.5.7 Sample code In ABAP This structural code demonstrates the Singleton pattern which assures only a single instance (the singleton) of the class can be created. *&---------------------------------------------------------------------* *& Report ZSINGLETON_STRUCTURAL *& *&---------------------------------------------------------------------* *& *& Version: 1.0 Side: 60

Project: Design Pattern *&---------------------------------------------------------------------* REPORT

zsingleton_structural.

*----------------------------------------------------------------------* * CLASS singleton DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS singleton DEFINITION CREATE PRIVATE. PUBLIC SECTION. METHODS: constructor. CLASS-METHODS: instance RETURNING value(instance) TYPE REF TO singleton. PRIVATE SECTION. CLASS-DATA x_instance TYPE REF TO singleton. ENDCLASS. "singleton DEFINITION *----------------------------------------------------------------------* * CLASS singleton IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS singleton IMPLEMENTATION. METHOD constructor. ENDMETHOD. "constructor METHOD instance. IF x_instance IS INITIAL. CREATE OBJECT x_instance. ENDIF. instance = x_instance. ENDMETHOD. "instance ENDCLASS.

"singleton IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp IMPLEMENTATION. METHOD main. DATA: s1 TYPE REF TO singleton ,s2 TYPE REF TO singleton . *

Constructor is protected --- cannot use create object s1 = singleton=>instance( ). s2 = singleton=>instance( ). IF s1 = s2. WRITE: / 'Objects are the same instance'. ENDIF.

Version: 1.0 Side: 61

Project: Design Pattern

ENDMETHOD. ENDCLASS.

"endmethod "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ). -----------------------------------Objects are the same instance

2.1.5.8 Sample code In C# This real-world code demonstrates the Singleton pattern as a LoadBalancing object. Only a single instance (the singleton) of the class can be created because servers may dynamically come on- or off-line and every request must go throught the one object that has knowledge about the state of the (web) farm. // Singleton pattern -- Real World example using System; using System.Collections; using System.Threading; namespace DoFactory.GangOfFour.Singleton.RealWorld { // MainApp test application class MainApp { static void Main() { LoadBalancer b1 = LoadBalancer b2 = LoadBalancer b3 = LoadBalancer b4 =

LoadBalancer.GetLoadBalancer(); LoadBalancer.GetLoadBalancer(); LoadBalancer.GetLoadBalancer(); LoadBalancer.GetLoadBalancer();

// Same instance? if (b1 == b2 && b2 == b3 && b3 == b4) { Console.WriteLine("Same instance\n"); } // All are the same instance -- use b1 arbitrarily // Load balance 15 server requests for (int i = 0; i < 15; i++) { Console.WriteLine(b1.Server); } // Wait for user Console.Read(); } }

Version: 1.0 Side: 62

Project: Design Pattern // "Singleton" class LoadBalancer { private static LoadBalancer instance; private ArrayList servers = new ArrayList(); private Random random = new Random(); // Lock synchronization object private static object syncLock = new object(); // Constructor (protected) protected LoadBalancer() { // List of available servers servers.Add("ServerI"); servers.Add("ServerII"); servers.Add("ServerIII"); servers.Add("ServerIV"); servers.Add("ServerV"); } public static LoadBalancer GetLoadBalancer() { // Support multithreaded applications through // 'Double checked locking' pattern which (once // the instance exists) avoids locking each // time the method is invoked if (instance == null) { lock (syncLock) { if (instance == null) { instance = new LoadBalancer(); } } } return instance; } // Simple, but effective random load balancer public string Server { get { int r = random.Next(servers.Count); return servers[r].ToString(); } } } }

Version: 1.0 Side: 63

Project: Design Pattern

Output Same instance ServerIII ServerII ServerI ServerII ServerI ServerIII ServerI ServerIII ServerIV ServerII ServerII ServerIII ServerIV ServerII ServerIV

2.1.5.9 Sample code In ABAP This real-world code demonstrates the Singleton pattern as a LoadBalancing object. Only a single instance (the singleton) of the class can be created because servers may dynamically come on- or off-line and every request must go throught the one object that has knowledge about the state of the (web) farm. *&---------------------------------------------------------------------* *& Report ZSINGLETON_STRUCTURAL *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT

zsingleton_structural.

*----------------------------------------------------------------------* * CLASS loadbalancer DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS loadbalancer DEFINITION CREATE PRIVATE. PUBLIC SECTION. METHODS: constructor ,server RETURNING value(pserver) TYPE string . CLASS-METHODS: getloadbalancer RETURNING value(instance) TYPE REF TO loadbalancer. PRIVATE SECTION. CLASS-DATA x_instance TYPE REF TO loadbalancer. DATA: servers TYPE TABLE OF string . METHODS: add IMPORTING servername TYPE string ,get RETURNING value(servername) TYPE string . ENDCLASS. "singleton DEFINITION *----------------------------------------------------------------------* Version: 1.0 Side: 64

Project: Design Pattern * CLASS loadbalancer IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS loadbalancer IMPLEMENTATION. METHOD constructor. * Create 5 servers add( EXPORTING servername = 'Server I' ). add( EXPORTING servername = 'Server II' ). add( EXPORTING servername = 'Server III' ). add( EXPORTING servername = 'Server IV' ). add( EXPORTING servername = 'Server V' ). ENDMETHOD.

"constructor

METHOD getloadbalancer. IF x_instance IS INITIAL. CREATE OBJECT x_instance. ENDIF. instance = x_instance. ENDMETHOD. "instance METHOD add. INSERT servername INTO TABLE servers. ENDMETHOD. "add METHOD get. DATA: numofservers TYPE i ,serverindex TYPE i ,random TYPE REF TO cl_abap_random ,seed TYPE i . seed = cl_abap_random=>seed( ). random = cl_abap_random=>create( seed ). DESCRIBE TABLE servers LINES numofservers. TRY. serverindex = random->intinrange( low = 1 high = numofservers ). CATCH cx_abap_random . ENDTRY. READ TABLE servers INDEX serverindex INTO servername. ENDMETHOD. "get METHOD server. pserver = me->get( ). ENDMETHOD. ENDCLASS.

"server "singleton IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* Version: 1.0 Side: 65

Project: Design Pattern CLASS mainapp IMPLEMENTATION. METHOD main. DATA: b1 TYPE REF TO loadbalancer ,b2 TYPE REF TO loadbalancer ,b3 TYPE REF TO loadbalancer ,b4 TYPE REF TO loadbalancer ,i TYPE i ,s TYPE string . *

Constructor is protected --- cannot b1 = loadbalancer=>getloadbalancer( b2 = loadbalancer=>getloadbalancer( b3 = loadbalancer=>getloadbalancer( b4 = loadbalancer=>getloadbalancer(

use create object ). ). ). ).

IF b1 = b2 AND b2 = b3 AND b3 = b4 . WRITE: / 'Objects are the same instance'. ENDIF. *

All are the same server, use b1 arbitraily DO 15 TIMES. s = b1->server( ). WRITE: / s. ENDDO.

ENDMETHOD. ENDCLASS.

"endmethod "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ). Objects are the same instance Server IV Server V Server III Server III Server I Server V Server I Server IV Server III Server II Server II Server IV Server I Server II Server V

2.1.5.10

Sample code In ABAP for Application

If you wish your program uses the object oriented paragime fully, you should probaly use a main application class. This class should follow the singleton pattern, as you probaly does not whish your program are able to start severel application sessions. I suggest you allways use local application class, since the singleton have severe problems with inheritage. Give your application class the name lcl_application. As singleton pattern describe, your class should be registered

Version: 1.0 Side: 66

Project: Design Pattern as CREATE PRIVATE. The default static method should be name RUN() without parameters. CLASS lcl_application DEFINITION CREATE PRIVATE. ENDCLASS.

2.2 Structural Patterns 2.2.1 Adapter Match interfaces of different classes

2.2.1.1 Definition Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces. In computer programming, the adapter design pattern (often referred to as the wrapper pattern or simply a wrapper) 'adapts' one interface for a class into one that a client expects. An adapter allows classes to work together that normally could not because of incompatible interfaces by wrapping its own interface around that of an already existing class. The adapter is also responsible for handling any logic necessary to transform data into a form that is useful for the consumer. For instance, if multiple boolean values are stored as a single integer but your consumer requires a 'true'/'false', the adapter would be responsible for extracting the appropriate values from the integer value. There are two types of adapter patterns: •

The Object Adapter pattern - In this type of adapter pattern, the adapter contains an instance of the class it wraps. In this situation, the adapter makes calls to the instance of the wrapped object.



The Class Adapter pattern - This type of adapter uses multiple inheritance to achieve its goal. The adapter is created inheriting interfaces from both the interface that is expected and the interface that is pre-existing. Note that when the adapter must adapt multiple adaptees, the Class Adapter pattern cannot be used in languages such as Java that do not support multiple inheritance.

Version: 1.0 Side: 67

Project: Design Pattern

ObjectAdapter

ClassAdapter

The object adapter pattern expressed in UML. The adapter hides the adaptee's interface from the client.

The class adapter pattern expressed in UML.

The adapter pattern is useful in situations where an already existing class provides some or all of the services you need but does not use the interface you need. A good real life example is an adapter that converts the interface of a Document Object Model of an XML document into a tree structure that can be displayed.

2.2.1.2 Common Use The ABAP language does not support multiple inheritage, but support interfaces. With interfaces you are able to use the same interface in different classes. You are also able to let one class use different and several interfaces and thereby accomplish the same effect as in multiple inheritage. A typical solution in SAP where you want to use adapters are when you in a dialog application want to have an object tree shown in the left control. This tree might have different objects to show. Therefore you create a number of interfaces that all the objects involved should be able to respond to e.g. open or show yourself. Every objects that can be part of the tree implement the interface.

Version: 1.0 Side: 68

Project: Design Pattern

2.2.1.3 UML class diagram

2.2.1.4 Participants The classes and/or objects participating in this pattern are: o Target (ChemicalCompound) o defines the domain-specific interface that Client uses. o Adapter (Compound) o adapts the interface Adaptee to the Target interface. o Adaptee (ChemicalDatabank) o defines an existing interface that needs adapting. o Client (AdapterApp) o collaborates with objects conforming to the Target interface.

2.2.1.5 Sample code In C# This structural code demonstrates the Adapter pattern which maps the interface of one class onto another so that they can work together. These incompatible classes may come from different libraries or frameworks. // Adapter pattern -- Structural example using System; namespace DoFactory.GangOfFour.Adapter.Structural { // Mainapp test application class MainApp { static void Main() { // Create adapter and place a request Target target = new Adapter(); target.Request(); Version: 1.0 Side: 69

Project: Design Pattern

// Wait for user Console.Read(); } } // "Target" class Target { public virtual void Request() { Console.WriteLine("Called Target Request()"); } } // "Adapter" class Adapter : Target { private Adaptee adaptee = new Adaptee(); public override void Request() { // Possibly do some other work // and then call SpecificRequest adaptee.SpecificRequest(); } } // "Adaptee" class Adaptee { public void SpecificRequest() { Console.WriteLine("Called SpecificRequest()"); } } }

Output Called SpecificRequest()

2.2.1.6 Sample code In ABAP This structural code demonstrates the Adapter pattern which maps the interface of one class onto another so that they can work together. These incompatible classes may come from different libraries or frameworks.

*&---------------------------------------------------------------------* *& Report ZDP_ADAPTER_STRUCTURAL

Version: 1.0 Side: 70

Project: Design Pattern *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT zdp_adapter_structural. *----------------------------------------------------------------------* * CLASS target DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS target DEFINITION. PUBLIC SECTION. METHODS: request. ENDCLASS. "target DEFINITION *----------------------------------------------------------------------* * CLASS target IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS target IMPLEMENTATION. METHOD request. WRITE: / 'Called Target Request()'. ENDMETHOD. "request ENDCLASS. "target IMPLEMENTATION *----------------------------------------------------------------------* * CLASS adaptee DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS adaptee DEFINITION. PUBLIC SECTION. METHODS: specificrequest. ENDCLASS. "adaptee DEFINITION *----------------------------------------------------------------------* * CLASS adaptee IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS adaptee IMPLEMENTATION. METHOD specificrequest. WRITE: / 'Called SpecificRequest()'. ENDMETHOD. "specificrequest ENDCLASS. "adaptee IMPLEMENTATION *----------------------------------------------------------------------* * CLASS adapter DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS adapter DEFINITION INHERITING FROM target. PUBLIC SECTION. METHODS: constructor ,request REDEFINITION. PRIVATE SECTION. CLASS-DATA: adaptee TYPE REF TO adaptee. ENDCLASS. "adapter DEFINITION *----------------------------------------------------------------------* Version: 1.0 Side: 71

Project: Design Pattern * CLASS adapter IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS adapter IMPLEMENTATION. METHOD constructor. CALL METHOD super->constructor. CREATE OBJECT adaptee. ENDMETHOD. "constructor METHOD request. CALL METHOD adaptee->specificrequest( ). ENDMETHOD. "request ENDCLASS. "adapter IMPLEMENTATION *----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp IMPLEMENTATION. METHOD main. data: mytarget type REF TO target ,myadapter TYPE REF TO adapter . * create adapter and place request create OBJECT myadapter. *

Upcasting mytarget = myadapter. call METHOD mytarget->request( ).

ENDMETHOD. ENDCLASS.

"endmethod "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ).

OUTPUT: --------Called SpecificRequest()

2.2.1.7 Sample code In C# This real-world code demonstrates the use of a legacy chemical databank. Chemical compound objects access the databank through an Adapter interface // Adapter pattern -- Real World example

Version: 1.0 Side: 72

Project: Design Pattern using System; namespace DoFactory.GangOfFour.Adapter.RealWorld { // MainApp test application class MainApp { static void Main() { // Non-adapted chemical compound Compound stuff = new Compound("Unknown"); stuff.Display(); // Adapted chemical compounds Compound water = new RichCompound("Water"); water.Display(); Compound benzene = new RichCompound("Benzene"); benzene.Display(); Compound alcohol = new RichCompound("Alcohol"); alcohol.Display(); // Wait for user Console.Read(); } } // "Target" class Compound { protected string name; protected float boilingPoint; protected float meltingPoint; protected double molecularWeight; protected string molecularFormula; // Constructor public Compound(string name) { this.name = name; } public virtual void Display() { Console.WriteLine("\nCompound: {0} ------ ", name); } } // "Adapter" class RichCompound : Compound { Version: 1.0 Side: 73

Project: Design Pattern private ChemicalDatabank bank; // Constructor public RichCompound(string name) : base(name) { } public override void Display() { // Adaptee bank = new ChemicalDatabank(); boilingPoint = bank.GetCriticalPoint(name, "B"); meltingPoint = bank.GetCriticalPoint(name, "M"); molecularWeight = bank.GetMolecularWeight(name); molecularFormula = bank.GetMolecularStructure(name); base.Display(); Console.WriteLine(" Console.WriteLine(" Console.WriteLine(" Console.WriteLine("

Formula: {0}", molecularFormula); Weight : {0}", molecularWeight); Melting Pt: {0}", meltingPoint); Boiling Pt: {0}", boilingPoint);

} } // "Adaptee" class ChemicalDatabank { // The Databank 'legacy API' public float GetCriticalPoint(string compound, string point) { float temperature = 0.0F; // Melting Point if (point == "M") { switch (compound.ToLower()) { case "water" : temperature = case "benzene" : temperature case "alcohol" : temperature } } // Boiling Point else { switch (compound.ToLower()) { case "water" : temperature = case "benzene" : temperature case "alcohol" : temperature } } return temperature; }

Version: 1.0 Side: 74

0.0F; break; = 5.5F; break; = -114.1F; break;

100.0F; break; = 80.1F; break; = 78.3F; break;

Project: Design Pattern public string GetMolecularStructure(string compound) { string structure = ""; switch { case case case } return

(compound.ToLower()) "water" : structure = "H20"; break; "benzene" : structure = "C6H6"; break; "alcohol" : structure = "C2H6O2"; break; structure;

} public double GetMolecularWeight(string compound) { double weight = 0.0; switch (compound.ToLower()) { case "water" : weight = 18.015; break; case "benzene" : weight = 78.1134; break; case "alcohol" : weight = 46.0688; break; } return weight; } } }

Output Compound: Unknown -----Compound: Water -----Formula: H20 Weight : 18.015 Melting Pt: 0 Boiling Pt: 100 Compound: Benzene -----Formula: C6H6 Weight : 78.1134 Melting Pt: 5.5 Boiling Pt: 80.1 Compound: Alcohol -----Formula: C2H6O2 Weight : 46.0688 Melting Pt: -114.1 Boiling Pt: 78.3

2.2.1.8 Sample code In ABAP This real-world code demonstrates the use of a legacy chemical databank. Chemical compound objects access the databank through an Adapter interface *&---------------------------------------------------------------------* *& Report ZDP_ADAPTER_REALWORLD *& Version: 1.0 Side: 75

Project: Design Pattern *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT zdp_adapter_zdp_adapter_realworld. TYPES: _float TYPE float ,_double TYPE p LENGTH 4 DECIMALS 4 ,_string TYPE string. *----------------------------------------------------------------------* * CLASS compound DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS compound DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING name TYPE _string ,display. PROTECTED SECTION. DATA: name TYPE _string ,boilingpoint TYPE _float ,meltingpoint TYPE _float ,molecularweight TYPE _double ,molecularformula TYPE _string . ENDCLASS. "compound DEFINITION *----------------------------------------------------------------------* * CLASS compound IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS compound IMPLEMENTATION. METHOD constructor. me->name = name. ENDMETHOD. "constructor METHOD display. WRITE: /, /2(30)'Compound: -----', name . ENDMETHOD. "display ENDCLASS.

"compound IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS chemicaldatabank DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS chemicaldatabank DEFINITION. PUBLIC SECTION. METHODS: getcriticalpoint IMPORTING compound TYPE _string point TYPE _string RETURNING value(temperature) TYPE _float ,getmolecularstructure IMPORTING compound TYPE _string RETURNING value(structure) TYPE _string ,getmolecularweight IMPORTING compound TYPE _string RETURNING value(weight) TYPE _double . ENDCLASS. "adaptee DEFINITION

Version: 1.0 Side: 76

Project: Design Pattern *----------------------------------------------------------------------* * CLASS chemicaldatabank IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS chemicaldatabank IMPLEMENTATION. METHOD getcriticalpoint. CLEAR temperature . CASE point. WHEN 'M'. CASE compound. WHEN 'Water'. temperature = '0.0'. WHEN 'Benzene'. temperature = '5.5'. WHEN 'Alcohol'. temperature = '-114.1'. WHEN OTHERS. ENDCASE. WHEN OTHERS. CASE compound. WHEN 'Water'. temperature = '100.0'. WHEN 'Benzene'. temperature = '80.1'. WHEN 'Alcohol'. temperature = '78.3'. WHEN OTHERS. temperature = temperature. ENDCASE. ENDCASE. ENDMETHOD. "specificrequest METHOD getmolecularstructure. CLEAR structure . CASE compound. WHEN 'Water'. structure = 'H2O'. WHEN 'Benzene'. structure = 'C6H6'. WHEN 'Alcohol'. structure = 'C2H6O2'. WHEN OTHERS. structure = structure. ENDCASE. ENDMETHOD. "getmolecularstructure METHOD getmolecularweight. CLEAR weight. CASE compound. WHEN 'Water'. weight = '18.015'. WHEN 'Benzene'. weight = '78.1134'. WHEN 'Alcohol'. weight = '46.0688'. WHEN OTHERS. weight = weight. ENDCASE. ENDMETHOD. ENDCLASS.

"getmolecularweight "adaptee IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS Richcompound DEFINITION *----------------------------------------------------------------------* Version: 1.0 Side: 77

Project: Design Pattern * *----------------------------------------------------------------------* CLASS richcompound DEFINITION INHERITING FROM compound. PUBLIC SECTION. METHODS: constructor IMPORTING name TYPE string ,display REDEFINITION. PRIVATE SECTION. DATA: bank TYPE REF TO chemicaldatabank. ENDCLASS.

"Richcompound DEFINITION

*----------------------------------------------------------------------* * CLASS Richcompound IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS richcompound IMPLEMENTATION. METHOD constructor. CALL METHOD super->constructor EXPORTING name = name. CREATE OBJECT bank. ENDMETHOD. "constructor METHOD display. boilingpoint = bank->getcriticalpoint( compound = me->name point = 'B' ). meltingpoint = bank->getcriticalpoint( compound = me->name point = 'M' ). molecularweight = bank->getmolecularweight( me->name ). molecularformula = bank->getmolecularstructure( me->name ). CALL METHOD super->display( ). WRITE: /5(30) 'Formula:' , molecularformula. WRITE: /5(30) 'Weight:' , molecularweight . WRITE: /5(30) 'Melting Pt:', meltingpoint DECIMALS 2 EXPONENT 0. WRITE: /5(30) 'Boiling Pt:', boilingpoint DECIMALS 2 EXPONENT 0. ENDMETHOD. ENDCLASS.

"request "Richcompound IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp IMPLEMENTATION. METHOD main. DATA: mystuff TYPE REF TO compound ,mywater TYPE REF TO richcompound ,mybenzene TYPE REF TO richcompound ,myalcohol TYPE REF TO richcompound . Version: 1.0 Side: 78

Project: Design Pattern *

create Richcompound and place request CREATE OBJECT mystuff EXPORTING name = 'Unknown'. mystuff->display( ). CREATE OBJECT mywater EXPORTING name = 'Water'. mywater->display( ). CREATE OBJECT mybenzene EXPORTING name = 'Benzene'. mybenzene->display( ). CREATE OBJECT myalcohol EXPORTING name = 'Alcohol'. myalcohol->display( ).

ENDMETHOD. ENDCLASS.

"endmethod "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ). OUTPUT: --------

Compound:

Unknown

Compound: Formula: Weight: Melting Pt: Boiling Pt:

Water H2O 18,0150

Compound: Formula: Weight: Melting Pt: Boiling Pt:

Benzene C6H6 78,1134

Compound: Formula: Weight: Melting Pt: Boiling Pt:

Alcohol C2H6O2 46,0688

0,00 100,00

5,50 80,10

-114,10 78,30

2.2.1.9 Sample code In ABAP using interfaces This real-world code demonstrates the use of a an Adapter interface. Wh have three grafihical elements the square, triangle and circle and the client want to get the elements area by using the same interface GET_AREA(). *&---------------------------------------------------------------------* *& Report ZDP_ADAPTER_EKSEMPEL *& *&---------------------------------------------------------------------* *& Exampel of the use of ADAPTER patterns. In this application we have *& 3 different classes circle, triangle and square. These 3 grafical *& elements obviously have different attributes and behavior. But from *& the clients point of view, it would make sence to ask each element *& what the area was. In abap this is best done through interfaces. Here *& we need the interface GET_AREAL() as a commond method for all three *& grafihical elements. In the example I also uses aliases to make the *& use more simpel from the element implementation. *&---------------------------------------------------------------------* Version: 1.0 Side: 79

Project: Design Pattern

REPORT

zdp_adapter_eksempel.

*----------------------------------------------------------------------* * INTERFACE lif_figur *----------------------------------------------------------------------* * *----------------------------------------------------------------------* INTERFACE lif_figur. METHODS: get_areal RETURNING value(areal) TYPE i. ENDINTERFACE. "lif_figur *----------------------------------------------------------------------* * CLASS lcl_cirkel DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS lcl_cirkel DEFINITION. PUBLIC SECTION. DATA: radius TYPE i. INTERFACES: lif_figur. ALIASES get_areal FOR lif_figur~get_areal. METHODS: constructor IMPORTING r TYPE i. ENDCLASS. "lcl_cirkel DEFINITION *----------------------------------------------------------------------* * CLASS lcl_cirkel IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS lcl_cirkel IMPLEMENTATION. METHOD constructor. me->radius = r. ENDMETHOD. "constructor METHOD get_areal. DATA: pi TYPE f. pi = 22 / 7. areal = ( me->radius ** 2 ) * pi. ENDMETHOD. "get_areal ENDCLASS. "lcl_cirkel IMPLEMENTATION *----------------------------------------------------------------------* * CLASS lcl_firkant DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS lcl_firkant DEFINITION. PUBLIC SECTION. DATA: laengde TYPE i ,bredde TYPE i. INTERFACES: lif_figur. ALIASES get_areal FOR lif_figur~get_areal. METHODS: constructor IMPORTING l TYPE i b TYPE i. ENDCLASS. "lcl_firkant DEFINITION

Version: 1.0 Side: 80

Project: Design Pattern *----------------------------------------------------------------------* * CLASS lcl_firkant IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS lcl_firkant IMPLEMENTATION. METHOD constructor. me->laengde = l. me->bredde = b. ENDMETHOD. "constructor METHOD get_areal. areal = me->laengde * me->bredde. ENDMETHOD. "get_areal ENDCLASS. "lcl_firkant IMPLEMENTATION *----------------------------------------------------------------------* * CLASS lcl_trekant DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS lcl_trekant DEFINITION. PUBLIC SECTION. DATA: hojde TYPE i ,grundlinie TYPE i. INTERFACES: lif_figur. ALIASES get_areal FOR lif_figur~get_areal. METHODS: constructor IMPORTING h TYPE i g TYPE i. ENDCLASS. "lcl_trekant DEFINITION *----------------------------------------------------------------------* * CLASS lcl_trekant IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS lcl_trekant IMPLEMENTATION. METHOD constructor. me->hojde = h. me->grundlinie = g. ENDMETHOD. "constructor METHOD get_areal. areal = ( me->hojde / 2 ) * me->grundlinie. ENDMETHOD. "get_areal ENDCLASS. "lcl_trekant IMPLEMENTATION *---------------------------------------------------------* CLASS lcl_application DEFINITION * Pattern: SINGLETON * Why: Definition create private ensures that nobody outside the * class can create instances unless the class-method run() * is activated and this method checks if an instance has * allready been created. *---------------------------------------------------------CLASS lcl_application DEFINITION CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS: run. METHODS: constructor. PRIVATE SECTION. CLASS-DATA: so_application TYPE REF TO lcl_application.

Version: 1.0 Side: 81

Project: Design Pattern DATA: ENDCLASS.

io_name

TYPE string. "lcl_application DEFINITION

*---------------------------------------------------------* IMPLEMENTATION *---------------------------------------------------------CLASS lcl_application IMPLEMENTATION. *---------------------------------------------------------* LCL_APPLICATION->RUN(). *---------------------------------------------------------METHOD run. DATA: exc_ref TYPE REF TO cx_root ,exc_text TYPE string . IF lcl_application=>so_application IS INITIAL. TRY. CREATE OBJECT lcl_application=>so_application. CATCH cx_sy_create_object_error INTO exc_ref. exc_text = exc_ref->get_text( ). MESSAGE exc_text TYPE 'I'. ENDTRY. ENDIF. ENDMETHOD. "run *---------------------------------------------------------* LCL_APPLICATION->CONSTRUCTOR(). * Use the constructor for instantiating internal objects, * fields, tables and events. *---------------------------------------------------------METHOD constructor. DATA: o_cirkel TYPE REF TO lcl_cirkel ,o_firkant TYPE REF TO lcl_firkant ,o_trekant TYPE REF TO lcl_trekant ,areal TYPE i . *

Først danner vi objekt referencerne CREATE OBJECT o_cirkel EXPORTING r CREATE OBJECT o_trekant EXPORTING h CREATE OBJECT o_firkant EXPORTING l

på de enkelte figurer = 24. = 2 g = 4. = 4 b = 5.

*

Sa beder vi objekterne om at fortælle deres areal. areal = o_cirkel->get_areal( ). WRITE:/ 'Cirklens areal er ', areal. areal = o_trekant->get_areal( ). WRITE:/ 'Trekantens areal er ', areal. areal = o_firkant->get_areal( ). WRITE:/ 'Firkantens areal er ', areal. ENDMETHOD.

ENDCLASS. START-OF-SELECTION.

Version: 1.0 Side: 82

"constructor "lcl_application IMPLEMENTATION

Project: Design Pattern lcl_application=>run( ).

2.2.2 Bridge Separates an object’s interface from its implementation

2.2.2.1 Definition The bridge pattern is a design pattern used in software engineering which is meant to "decouple an abstraction from its implementation so that the two can vary independently" (Gamma et al.). The bridge uses encapsulation, aggregation, and can use inheritance to separate responsibilities into different classes. When a class varies often, the features of object-oriented programming become very useful because changes to a program's code can be made easily with minimal prior knowledge about the program. The bridge pattern is useful when not only the class itself varies often but also what the class does. The class itself can be thought of as the abstraction and what the class can do as the implementation. Variant: The implementation can be decoupled even more by deferring the presence of the implementation to the point where the abstraction is utilized (as illustrated by the Visual Prolog example below).

2.2.2.2 Common Use Shape abstraction When the abstraction and implementation are separated, they can vary independently. Consider the abstraction of shapes. There are many types of shapes, each with its own properties. And there are things that all shapes do. One thing all shapes can do is draw themselves. However, drawing graphics to a screen can sometimes be dependent on different graphics implementations or operating systems. Shapes have to be able to be drawn on many types of systems. Having the shape itself implement them all, or modifying the shape class to work with different architectures is not practical. The bridge helps by allowing the creation of new classes that provide the drawing implementation. The abstract class, shape, provides methods for getting the size or properties of a shape. The implementation class, drawing, provides an interface for drawing graphics. If a new shape needs to be created or there is a new graphics API to be drawn on, then it is very easy to add a new class that implements the needed features.[ Car abstraction

Version: 1.0 Side: 83

Project: Design Pattern Imagine two types of cars (the abstraction), a Jaguar and a Mercedes (both are Refinements of the Abstraction). The Abstraction defines that a Car has features such as tires and an engine. Refinements of the Abstraction declare what specific kind of tires and engine it has. Finally, there are two types of road. The road is the Implementor (see image below). A highway and an interstate highway are the Implementation Details. Any car refinement needs to be able to drive on any type of road; this concept is what the Bridge Pattern is all about.

2.2.2.3 UML class diagram

class diagram of the bridge design pattern, created by Nvineeth using dpatoolkit

2.2.2.4 Participants 2.2.2.5 Sample code In C# 2.2.3 Composite A tree structure of simple and composite objects

2.2.3.1 Definition Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly. The example could be more accurate, as the leaf can neither remove or add, and therefore these methods should not be part of the component butmoved to the composite, the only common methods are the constructor and display.

Version: 1.0 Side: 84

Project: Design Pattern

2.2.3.2 UML class diagram

2.2.3.3 Participants The classes and/or objects participating in this pattern are: • Component (DrawingElement) o declares the interface for objects in the composition. implements default behavior for the interface common to all classes, as appropriate. declares an interface for accessing and managing its child components. (optional) defines an interface for accessing a component's parent in the recursive structure, and implements it if that's appropriate. • Leaf (PrimitiveElement) o represents leaf objects in the composition. A leaf has no children. defines behavior for primitive objects in the composition. • Composite (CompositeElement) o defines behavior for components having children. stores child components. implements child-related operations in the Component interface. • Client (CompositeApp) o manipulates objects in the composition through the Component interface.

2.2.3.4 Sample code In C# This structural code demonstrates the Composite pattern which allows the creation of a tree structure in which individual nodes are accessed uniformly whether they are leaf nodes or branch (composite) nodes.

Version: 1.0 Side: 85

Project: Design Pattern

// Composite pattern -- Structural example using System; using System.Collections; namespace DoFactory.GangOfFour.Composite.Structural { // MainApp test application class MainApp { static void Main() { // Create a tree structure Composite root = new Composite("root"); root.Add(new Leaf("Leaf A")); root.Add(new Leaf("Leaf B")); Composite comp = new Composite("Composite X"); comp.Add(new Leaf("Leaf XA")); comp.Add(new Leaf("Leaf XB")); root.Add(comp); root.Add(new Leaf("Leaf C")); // Add and remove a leaf Leaf leaf = new Leaf("Leaf D"); root.Add(leaf); root.Remove(leaf); // Recursively display tree root.Display(1); // Wait for user Console.Read(); } } // "Component" abstract class Component { protected string name; // Constructor public Component(string name) { this.name = name; } public abstract void Add(Component c); public abstract void Remove(Component c); public abstract void Display(int depth); }

Version: 1.0 Side: 86

Project: Design Pattern // "Composite" class Composite : Component { private ArrayList children = new ArrayList(); // Constructor public Composite(string name) : base(name) { } public override void Add(Component component) { children.Add(component); } public override void Remove(Component component) { children.Remove(component); } public override void Display(int depth) { Console.WriteLine(new String('-', depth) + name); // Recursively display child nodes foreach (Component component in children) { component.Display(depth + 2); } } } // "Leaf" class Leaf : Component { // Constructor public Leaf(string name) : base(name) { } public override void Add(Component c) { Console.WriteLine("Cannot add to a leaf"); } public override void Remove(Component c) { Console.WriteLine("Cannot remove from a leaf"); } public override void Display(int depth) { Console.WriteLine(new String('-', depth) + name); } Version: 1.0 Side: 87

Project: Design Pattern } }

Output -root ---Leaf A ---Leaf B ---Composite X -----Leaf XA -----Leaf XB ---Leaf C

2.2.3.5 Sample code In ABAP This structural code demonstrates the Composite pattern which allows the creation of a tree structure in which individual nodes are accessed uniformly whether they are leaf nodes or branch (composite) nodes. *&---------------------------------------------------------------------* *& Report ZDP_COMPOSITE_STRUCTURAL *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT zdp_composite_structural. *----------------------------------------------------------------------* * CLASS component DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS component DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: constructor IMPORTING name TYPE string ,add ABSTRACT IMPORTING component TYPE REF TO component ,remove ABSTRACT IMPORTING component TYPE REF TO component ,display ABSTRACT IMPORTING depth TYPE i . PROTECTED SECTION. DATA: name TYPE string. ENDCLASS. "component DEFINITION *----------------------------------------------------------------------* * CLASS component IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS component IMPLEMENTATION. METHOD constructor. me->name = name. ENDMETHOD. "constructor ENDCLASS. "component IMPLEMENTATION *----------------------------------------------------------------------* * CLASS composite DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS composite DEFINITION INHERITING FROM component. PUBLIC SECTION. Version: 1.0 Side: 88

Project: Design Pattern METHODS: add REDEFINITION ,remove REDEFINITION ,display REDEFINITION . CLASS-METHODS: new IMPORTING name TYPE string RETURNING value(composite) TYPE REF TO composite . PRIVATE SECTION. DATA children TYPE TABLE OF REF TO component. ENDCLASS. "composite DEFINITION *----------------------------------------------------------------------* * CLASS composite IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS composite IMPLEMENTATION. METHOD add. INSERT component INTO TABLE children. ENDMETHOD. "add METHOD remove. FIELD-SYMBOLS TYPE REF TO component. data: index type sy-tabix. LOOP AT children ASSIGNING . index = sy-tabix. IF = component. EXIT. ENDIF. ENDLOOP. IF sy-subrc = 0. DELETE children INDEX index. ENDIF. ENDMETHOD. "remove METHOD display. FIELD-SYMBOLS TYPE REF TO component. DATA mydepth TYPE i. write: /. do depth times. write '-'. enddo. WRITE: me->name. mydepth = depth + 1. LOOP AT children ASSIGNING . ->display( EXPORTING depth = mydepth ). ENDLOOP. ENDMETHOD. "display METHOD new. CREATE OBJECT composite EXPORTING name = name. ENDMETHOD. "new ENDCLASS.

"composite IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS leaf DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS leaf DEFINITION INHERITING FROM component. PUBLIC SECTION. Version: 1.0 Side: 89

Project: Design Pattern METHODS: add REDEFINITION ,remove REDEFINITION ,display REDEFINITION . CLASS-METHODS: new IMPORTING name TYPE string RETURNING value(leaf) TYPE REF TO leaf . ENDCLASS. "leaf DEFINITION *----------------------------------------------------------------------* * CLASS leaf IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS leaf IMPLEMENTATION. METHOD add. WRITE: / 'Cannot add to a leaf'. ENDMETHOD. "add METHOD remove. WRITE: / 'Cannot remove from a leaf'. ENDMETHOD. "remove METHOD display. write: /. do depth times. write '-'. enddo. WRITE: me->name. ENDMETHOD. "display METHOD new. CREATE OBJECT leaf EXPORTING name = name. ENDMETHOD. "new ENDCLASS. "leaf IMPLEMENTATION *----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp IMPLEMENTATION. METHOD main. DATA: myroot TYPE REF TO composite ,myleaf TYPE REF TO leaf ,mycomposite TYPE REF TO composite . myroot = composite=>new('root'). myleaf = leaf=>new('Leaf A'). myleaf = leaf=>new('Leaf B').

myroot->add( myleaf ). myroot->add( myleaf ).

mycomposite = composite=>new('Composite X'). myleaf = leaf=>new('Leaf XA'). mycomposite->add( myleaf ). myleaf = leaf=>new('Leaf XB'). mycomposite->add( myleaf ). myroot->add( mycomposite ). myleaf = leaf=>new('Leaf C'). Version: 1.0 Side: 90

myroot->add( myleaf ).

Project: Design Pattern

myleaf = leaf=>new('Leaf D'). myroot->remove( myleaf ).

myroot->add( myleaf ).

myroot->display( 1 ). ENDMETHOD. ENDCLASS.

"endmethod "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ). OUTPUT: - root - - Leaf A - - Leaf B - - Composite X - - - Leaf XA - - - Leaf XB - - Leaf C

2.2.3.6 Sample code In C# This real-world code demonstrates the Composite pattern used in building a graphical tree structure made up of primitive nodes (lines, circles, etc) and composite nodes (groups of drawing elements that make up more complex elements). using System; using System.Collections; namespace DoFactory.GangOfFour.Composite.RealWorld { // Mainapp test application class MainApp { static void Main() { // Create a tree structure CompositeElement root = new CompositeElement("Picture"); root.Add(new PrimitiveElement("Red Line")); root.Add(new PrimitiveElement("Blue Circle")); root.Add(new PrimitiveElement("Green Box")); CompositeElement comp = new CompositeElement("Two Circles"); comp.Add(new PrimitiveElement("Black Circle")); comp.Add(new PrimitiveElement("White Circle")); root.Add(comp); // Add and remove a PrimitiveElement PrimitiveElement pe = new PrimitiveElement("Yellow Line"); root.Add(pe); root.Remove(pe); // Recursively display nodes Version: 1.0 Side: 91

Project: Design Pattern root.Display(1); // Wait for user Console.Read(); } } // "Component" Treenode abstract class DrawingElement { protected string name; // Constructor public DrawingElement(string name) { this.name = name; } public abstract void Add(DrawingElement d); public abstract void Remove(DrawingElement d); public abstract void Display(int indent); } // "Leaf" class PrimitiveElement : DrawingElement { // Constructor public PrimitiveElement(string name) : base(name) { } public override void Add(DrawingElement c) { Console.WriteLine( "Cannot add to a PrimitiveElement"); } public override void Remove(DrawingElement c) { Console.WriteLine( "Cannot remove from a PrimitiveElement"); } public override void Display(int indent) { Console.WriteLine( new String('-', indent) + " " + name); } } // "Composite" class CompositeElement : DrawingElement { private ArrayList elements = new ArrayList(); // Constructor public CompositeElement(string name) : base(name) { } public override void Add(DrawingElement d) { elements.Add(d); Version: 1.0 Side: 92

Project: Design Pattern } public override void Remove(DrawingElement d) { elements.Remove(d); } public override void Display(int indent) { Console.WriteLine(new String('-', indent) + "+ " + name); // Display each child element on this node foreach (DrawingElement c in elements) { c.Display(indent + 2); } } } }

Output -+ Picture --- Red Line --- Blue Circle --- Green Box ---+ Two Circles ----- Black Circle ----- White Circle

2.2.3.7 Sample code In ABAP This real-world code demonstrates the Composite pattern used in building a graphical tree structure made up of primitive nodes (lines, circles, etc) and composite nodes (groups of drawing elements that make up more complex elements). *&---------------------------------------------------------------------* *& Report ZDP_COMPOSITE_REALWORLD *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT zdp_composite_realworld. *----------------------------------------------------------------------* * CLASS DrawingElement DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS drawingelement DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: constructor IMPORTING name TYPE string ,add ABSTRACT IMPORTING drawingelement TYPE REF TO drawingelement ,remove ABSTRACT IMPORTING drawingelement TYPE REF TO drawingelement ,display ABSTRACT IMPORTING indent TYPE i . PROTECTED SECTION. Version: 1.0 Side: 93

Project: Design Pattern DATA: name TYPE string. ENDCLASS.

"DrawingElement DEFINITION

*----------------------------------------------------------------------* * CLASS DrawingElement IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS drawingelement IMPLEMENTATION. METHOD constructor. me->name = name. ENDMETHOD. "constructor ENDCLASS. "DrawingElement IMPLEMENTATION *----------------------------------------------------------------------* * CLASS compositeElement DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS compositeelement DEFINITION INHERITING FROM drawingelement. PUBLIC SECTION. METHODS: add REDEFINITION ,remove REDEFINITION ,display REDEFINITION . CLASS-METHODS: new IMPORTING name TYPE string RETURNING value(compositeelement) TYPE REF TO compositeelement . PRIVATE SECTION. DATA elements TYPE TABLE OF REF TO drawingelement. ENDCLASS. "compositeElement DEFINITION *----------------------------------------------------------------------* * CLASS compositeElement IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS compositeelement IMPLEMENTATION. METHOD add. INSERT drawingelement INTO TABLE elements. ENDMETHOD. "add METHOD remove. FIELD-SYMBOLS TYPE REF TO drawingelement. DATA: index TYPE sy-tabix. LOOP AT elements ASSIGNING . index = sy-tabix. IF = drawingelement. EXIT. ENDIF. ENDLOOP. IF sy-subrc = 0. DELETE elements INDEX index. ENDIF. ENDMETHOD. "remove METHOD display. FIELD-SYMBOLS TYPE REF TO drawingelement. DATA myindent TYPE i. WRITE: /. DO indent TIMES. WRITE '-'. ENDDO. Version: 1.0 Side: 94

Project: Design Pattern WRITE:

'+' , me->name.

myindent = indent + 2. LOOP AT elements ASSIGNING . ->display( EXPORTING indent = myindent ). ENDLOOP. ENDMETHOD. "display METHOD new. CREATE OBJECT compositeelement EXPORTING name = name. ENDMETHOD. "new ENDCLASS.

"compositeElement IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS PrimitiveElement DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS primitiveelement DEFINITION INHERITING FROM drawingelement. PUBLIC SECTION. METHODS: add REDEFINITION ,remove REDEFINITION ,display REDEFINITION . CLASS-METHODS: new IMPORTING name TYPE string RETURNING value(primitiveelement) TYPE REF TO primitiveelement . ENDCLASS. "PrimitiveElement DEFINITION *----------------------------------------------------------------------* * CLASS PrimitiveElement IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS primitiveelement IMPLEMENTATION. METHOD add. WRITE: / 'Cannot add to a PrimitiveElement'. ENDMETHOD. "add METHOD remove. WRITE: / 'Cannot remove from a PrimitiveElement'. ENDMETHOD. "remove METHOD display. WRITE: /. DO indent TIMES. WRITE '-'. ENDDO. WRITE: me->name. ENDMETHOD. "display METHOD new. CREATE OBJECT primitiveelement EXPORTING name = name. ENDMETHOD. "new ENDCLASS. "PrimitiveElement IMPLEMENTATION *----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION

Version: 1.0 Side: 95

Project: Design Pattern *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp IMPLEMENTATION. METHOD main. DATA: myroot TYPE REF TO compositeelement ,myprimitiveelement TYPE REF TO primitiveelement ,mycompositeelement TYPE REF TO compositeelement . myroot = compositeelement=>new('Picture'). myprimitiveelement = primitiveelement=>new('Red Line'). myroot->add( myprimitiveelement ). myprimitiveelement = primitiveelement=>new('Blue Circle'). myroot->add( myprimitiveelement ). myprimitiveelement = primitiveelement=>new('Gree Box'). myroot->add( myprimitiveelement ). mycompositeelement = compositeelement=>new('Two Circles'). myprimitiveelement = primitiveelement=>new('Black Circle'). mycompositeelement->add( myprimitiveelement ). myprimitiveelement = primitiveelement=>new('White Circle'). mycompositeelement->add( myprimitiveelement ). myroot->add( mycompositeelement ). myprimitiveelement = primitiveelement=>new('Yellow Line'). myprimitiveelement ). myroot->remove( myprimitiveelement ).

myroot->add(

myroot->display( 1 ). ENDMETHOD. ENDCLASS.

"endmethod "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ). OUTPUT: -

+ -

Picture - Red Line - Blue Circle - Gree Box - + Two Circles - - - Black Circle - - - White Circle

2.2.4 Decorator Add responsibilities to objects dynamically

2.2.4.1 Definition Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

Version: 1.0 Side: 96

Project: Design Pattern

2.2.4.2 UML class diagram

2.2.4.3 Participants The classes and/or objects participating in this pattern are: • • •



Component (LibraryItem) o defines the interface for objects that can have responsibilities added to them dynamically. ConcreteComponent (Book, Video) o defines an object to which additional responsibilities can be attached. Decorator (Decorator) o maintains a reference to a Component object and defines an interface that conforms to Component's interface. ConcreteDecorator (Borrowable) o adds responsibilities to the component.

2.2.4.4 Sample code In C# This structural code demonstrates the Decorator pattern which dynamically adds extra functionality to an existing object. // Decorator pattern -- Structural example using System; namespace DoFactory.GangOfFour.Decorator.Structural {

Version: 1.0 Side: 97

Project: Design Pattern // MainApp test application class MainApp { static void Main() { // Create ConcreteComponent and two Decorators ConcreteComponent c = new ConcreteComponent(); ConcreteDecoratorA d1 = new ConcreteDecoratorA(); ConcreteDecoratorB d2 = new ConcreteDecoratorB(); // Link decorators d1.SetComponent(c); d2.SetComponent(d1); d2.Operation(); // Wait for user Console.Read(); } } // "Component" abstract class Component { public abstract void Operation(); } // "ConcreteComponent" class ConcreteComponent : Component { public override void Operation() { Console.WriteLine("ConcreteComponent.Operation()"); } } // "Decorator" abstract class Decorator : Component { protected Component component; public void SetComponent(Component component) { this.component = component; } public override void Operation() { if (component != null) { component.Operation(); } Version: 1.0 Side: 98

Project: Design Pattern } } // "ConcreteDecoratorA" class ConcreteDecoratorA : Decorator { private string addedState; public override void Operation() { base.Operation(); addedState = "New State"; Console.WriteLine("ConcreteDecoratorA.Operation()"); } } // "ConcreteDecoratorB" class ConcreteDecoratorB : Decorator { public override void Operation() { base.Operation(); AddedBehavior(); Console.WriteLine("ConcreteDecoratorB.Operation()"); } void AddedBehavior() { } } }

Output ConcreteComponent.Operation() ConcreteDecoratorA.Operation() ConcreteDecoratorB.Operation()

2.2.4.5 Sample code In ABAP This structural code demonstrates the Decorator pattern which dynamically adds extra functionality to an existing object. *&---------------------------------------------------------------------* *& Report ZDP_DECORATOR_STRUCTURAL *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT

zdp_decorator_structural.

*----------------------------------------------------------------------* * CLASS component DEFINITION *----------------------------------------------------------------------* Version: 1.0 Side: 99

Project: Design Pattern * *----------------------------------------------------------------------* CLASS component DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: operation ABSTRACT. ENDCLASS. "component DEFINITION *----------------------------------------------------------------------* * CLASS concretecomponent DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concretecomponent DEFINITION INHERITING FROM component. PUBLIC SECTION. METHODS: operation REDEFINITION. ENDCLASS. "concretecomponent DEFINITION *----------------------------------------------------------------------* * CLASS concretecomponent IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concretecomponent IMPLEMENTATION. METHOD operation. WRITE: / 'ConcreteComponent.Operation()'. ENDMETHOD. "operation ENDCLASS. "concretecomponent IMPLEMENTATION *----------------------------------------------------------------------* * CLASS decorator DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS decorator DEFINITION INHERITING FROM component ABSTRACT. PUBLIC SECTION. METHODS: setcomponent IMPORTING component TYPE REF TO component ,operation REDEFINITION . PROTECTED SECTION. DATA: component TYPE REF TO component. ENDCLASS. "decorator DEFINITION *----------------------------------------------------------------------* * CLASS decorator IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS decorator IMPLEMENTATION. METHOD setcomponent. me->component = component. ENDMETHOD. "setcomponent METHOD operation. IF NOT component IS INITIAL. component->operation( ). ENDIF. ENDMETHOD. "operation ENDCLASS. "decorator IMPLEMENTATION *----------------------------------------------------------------------* * CLASS concretedecoratora DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concretedecoratora DEFINITION INHERITING FROM decorator. Version: 1.0 Side: 100

Project: Design Pattern PUBLIC SECTION. METHODS: operation REDEFINITION. PRIVATE SECTION. DATA: addedstate TYPE string. ENDCLASS. "concretedecoratora DEFINITION *----------------------------------------------------------------------* * CLASS concretedecoratora IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concretedecoratora IMPLEMENTATION. METHOD operation. super->operation( ). addedstate = 'New State'. WRITE: / 'ConcreteDecoratorA.Operation()'. ENDMETHOD. "operation ENDCLASS. "concretedecoratora IMPLEMENTATION *----------------------------------------------------------------------* * CLASS concretedecoratorb DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concretedecoratorb DEFINITION INHERITING FROM decorator. PUBLIC SECTION. METHODS: operation REDEFINITION ,addedbehavior . ENDCLASS. "concretedecoratorb DEFINITION *----------------------------------------------------------------------* * CLASS concretedecoratorb IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concretedecoratorb IMPLEMENTATION. METHOD operation. super->operation( ). me->addedbehavior( ). WRITE: / 'ConcreteDecoratorB.Operation()'. ENDMETHOD. "operation METHOD addedbehavior. ENDMETHOD. "addedbehavior ENDCLASS. "concretedecoratorb IMPLEMENTATION *----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp IMPLEMENTATION. METHOD main. DATA: c TYPE REF TO concretecomponent ,d1 TYPE REF TO concretedecoratora Version: 1.0 Side: 101

Project: Design Pattern ,d2 TYPE . CREATE OBJECT CREATE OBJECT CREATE OBJECT

REF TO concretedecoratorb c. d1. d2.

d1->setcomponent( c ). d2->setcomponent( d1 ). d2->operation( ). ENDMETHOD. ENDCLASS.

"endmethod "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ). OUTPUT: --------------------ConcreteComponent.Operation() ConcreteDecoratorA.Operation() ConcreteDecoratorB.Operation()

2.2.4.6 Sample code In C# This real-world code demonstrates the Decorator pattern in which 'borrowable' functionality is added to existing library items (books and videos). // Decorator pattern -- Real World example using System; using System.Collections; namespace DoFactory.GangOfFour.Decorator.RealWorld { // MainApp test application class MainApp { static void Main() { // Create book Book book = new Book ("Worley", "Inside ASP.NET", 10); book.Display(); // Create video Video video = new Video ("Spielberg", "Jaws", 23, 92); video.Display(); // Make video borrowable, then borrow and display Console.WriteLine("\nMaking video borrowable:"); Borrowable borrowvideo = new Borrowable(video); borrowvideo.BorrowItem("Customer #1"); borrowvideo.BorrowItem("Customer #2"); borrowvideo.Display();

Version: 1.0 Side: 102

Project: Design Pattern

// Wait for user Console.Read(); } } // "Component" abstract class LibraryItem { private int numCopies; // Property public int NumCopies { get{ return numCopies; } set{ numCopies = value; } } public abstract void Display(); } // "ConcreteComponent" class Book : LibraryItem { private string author; private string title; // Constructor public Book(string author,string title,int numCopies) { this.author = author; this.title = title; this.NumCopies = numCopies; } public override void Display() { Console.WriteLine("\nBook ------ "); Console.WriteLine(" Author: {0}", author); Console.WriteLine(" Title: {0}", title); Console.WriteLine(" # Copies: {0}", NumCopies); } } // "ConcreteComponent" class Video : LibraryItem { private string director; private string title; private int playTime; // Constructor public Video(string director, string title, Version: 1.0 Side: 103

Project: Design Pattern int numCopies, int playTime) { this.director = director; this.title = title; this.NumCopies = numCopies; this.playTime = playTime; } public override void Display() { Console.WriteLine("\nVideo ----- "); Console.WriteLine(" Director: {0}", director); Console.WriteLine(" Title: {0}", title); Console.WriteLine(" # Copies: {0}", NumCopies); Console.WriteLine(" Playtime: {0}\n", playTime); } } // "Decorator" abstract class Decorator : LibraryItem { protected LibraryItem libraryItem; // Constructor public Decorator(LibraryItem libraryItem) { this.libraryItem = libraryItem; } public override void Display() { libraryItem.Display(); } } // "ConcreteDecorator" class Borrowable : Decorator { protected ArrayList borrowers = new ArrayList(); // Constructor public Borrowable(LibraryItem libraryItem) : base(libraryItem) { } public void BorrowItem(string name) { borrowers.Add(name); libraryItem.NumCopies--; } public void ReturnItem(string name) { Version: 1.0 Side: 104

Project: Design Pattern borrowers.Remove(name); libraryItem.NumCopies++; } public override void Display() { base.Display(); foreach (string borrower in borrowers) { Console.WriteLine(" borrower: " + borrower); } } } }

Output Book -----Author: Worley Title: Inside ASP.NET # Copies: 10 Video ----Director: Spielberg Title: Jaws # Copies: 23 Playtime: 92

Making video borrowable: Video ----Director: Spielberg Title: Jaws # Copies: 21 Playtime: 92 borrower: Customer #1 borrower: Customer #2

2.2.4.7 Sample code In ABAP This real-world code demonstrates the Decorator pattern in which 'borrowable' functionality is added to existing library items (books and videos). *&---------------------------------------------------------------------* *& Report ZDP_DECORATOR_REALWORLD *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT

zdp_decorator_realworld.

*----------------------------------------------------------------------* * CLASS property DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* Version: 1.0 Side: 105

Project: Design Pattern CLASS property DEFINITION. PUBLIC SECTION. DATA: value TYPE i. METHODS: get RETURNING value(value) TYPE i ,set IMPORTING value TYPE i . ENDCLASS. "property DEFINITION *----------------------------------------------------------------------* * CLASS property IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS property IMPLEMENTATION. METHOD get. value = me->value. ENDMETHOD. "get METHOD set. me->value = value. ENDMETHOD. "set ENDCLASS. "property IMPLEMENTATION *----------------------------------------------------------------------* * CLASS LibraryItem DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS libraryitem DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: constructor IMPORTING numcopies TYPE i ,display ABSTRACT. PROTECTED SECTION. DATA: numcopies TYPE REF TO property. ENDCLASS. "LibraryItem DEFINITION *----------------------------------------------------------------------* * CLASS libraryitem IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS libraryitem IMPLEMENTATION. METHOD constructor. CREATE OBJECT me->numcopies. me->numcopies->set( numcopies ). ENDMETHOD. "constructor ENDCLASS. "libraryitem IMPLEMENTATION *----------------------------------------------------------------------* * CLASS book DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS book DEFINITION INHERITING FROM libraryitem. PUBLIC SECTION. METHODS: constructor IMPORTING author TYPE string title TYPE string numcopies TYPE i ,display REDEFINITION. PRIVATE SECTION. DATA: author TYPE string ,title TYPE string Version: 1.0 Side: 106

Project: Design Pattern . ENDCLASS.

"book DEFINITION

*----------------------------------------------------------------------* * CLASS book IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS book IMPLEMENTATION. METHOD constructor. super->constructor( numcopies ). me->author = author. me->title = title. ENDMETHOD. "constructor METHOD display. DATA: numofcopies TYPE i. WRITE: /, /2(20)'Book ---------------'. WRITE: /5(15)'Author:........', author. WRITE: /5(15)'Title:.........', title. numofcopies = me->numcopies->get( ). WRITE: /5(15)'# copies:......' , numofcopies . ENDMETHOD. "display ENDCLASS.

"book IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS video DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS video DEFINITION INHERITING FROM libraryitem. PUBLIC SECTION. METHODS: constructor IMPORTING director TYPE string title TYPE string numcopies TYPE i playtime TYPE i ,display REDEFINITION. PRIVATE SECTION. DATA: director TYPE string ,title TYPE string ,playtime TYPE i . ENDCLASS. "video DEFINITION *----------------------------------------------------------------------* * CLASS video IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS video IMPLEMENTATION. METHOD constructor. super->constructor( numcopies ). me->director = director. me->title = title. me->playtime = playtime. ENDMETHOD. "constructor METHOD display. DATA: numofcopies TYPE i. WRITE: /, /2(20)'Video --------------'. WRITE: /5(15)'Director:......', director. WRITE: /5(15)'Title:.........', title. numofcopies = me->numcopies->get( ). Version: 1.0 Side: 107

Project: Design Pattern WRITE: /5(15)'# copies:......' , numofcopies . WRITE:/5(15)'Playtime:.......', playtime. ENDMETHOD. "display ENDCLASS.

"video IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS decorator DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS decorator DEFINITION INHERITING FROM libraryitem ABSTRACT. PUBLIC SECTION. METHODS: constructor IMPORTING libraryitem TYPE REF TO libraryitem ,display REDEFINITION . PROTECTED SECTION. DATA: libraryitem TYPE REF TO libraryitem. ENDCLASS. "decorator DEFINITION *----------------------------------------------------------------------* * CLASS decorator IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS decorator IMPLEMENTATION. METHOD constructor. super->constructor( 1 ). me->libraryitem = libraryitem. ENDMETHOD. "constructor METHOD display. me->libraryitem->display( ). ENDMETHOD. "display ENDCLASS.

"decorator IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS borrowable DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS borrowable DEFINITION INHERITING FROM decorator. PUBLIC SECTION. METHODS: borrowitem IMPORTING name TYPE string ,returnitem IMPORTING name TYPE string ,display REDEFINITION . PROTECTED SECTION. DATA borrowers TYPE TABLE OF string. ENDCLASS.

"borrowable DEFINITION

*----------------------------------------------------------------------* * CLASS borrowable IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS borrowable IMPLEMENTATION. METHOD borrowitem. DATA: numofcopies TYPE i. INSERT name INTO TABLE borrowers. Version: 1.0 Side: 108

Project: Design Pattern numofcopies = me->libraryitem->numcopies->get( ). SUBTRACT 1 FROM numofcopies. me->libraryitem->numcopies->set( numofcopies ). ENDMETHOD. "borrowitem METHOD returnitem. ENDMETHOD. METHOD display. DATA name TYPE string.

"returnitem

super->display( ). WRITE: /. LOOP AT borrowers INTO name. WRITE: /10(10)'Borrower:.', name. ENDLOOP. ENDMETHOD. "display ENDCLASS.

"borrowable IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp IMPLEMENTATION. METHOD main. DATA: book TYPE REF TO book ,video TYPE REF TO video ,borrowvideo TYPE REF TO borrowable . CREATE OBJECT book EXPORTING author = 'Worley' title = 'Inside ASP.NET' numcopies = 10. book->display( ). CREATE OBJECT video EXPORTING director title numcopies playtime video->display( ). *

= = = =

'Spielberg' 'Jaws' 23 92.

make video borrowable, then borrow and display WRITE: /, / 'Making Vide borrowable'. CREATE OBJECT borrowvideo EXPORTING libraryitem = video. borrowvideo->borrowitem( 'Customer #1' ). borrowvideo->borrowitem( 'Customer #2' ). borrowvideo->display( ).

ENDMETHOD. ENDCLASS. START-OF-SELECTION. mainapp=>main( ).

Version: 1.0 Side: 109

"endmethod "mainapp IMPLEMENTATION

Project: Design Pattern OUTPUT: ------Book Author:........ Worley Title:......... Inside ASP.NET # copies:...... 10 Video Director:...... Spielberg Title:......... Jaws # copies:...... 23 Playtime:...... 92 Making Vide borrowable Video Director:...... Spielberg Title:......... Jaws # copies:...... 21 Playtime:...... 92 Borrower:. Customer #1 Borrower:. Customer #2

2.2.5 Facade A single class that represents an entire subsystem

2.2.5.1 Definition Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use.

2.2.5.2 UML class diagram

2.2.5.3 Participants The classes and/or objects participating in this pattern are: Version: 1.0 Side: 110

Project: Design Pattern • •

Facade (MortgageApplication) o knows which subsystem classes are responsible for a request. delegates client requests to appropriate subsystem objects. Subsystem classes (Bank, Credit, Loan) o implement subsystem functionality. handle work assigned by the Facade object. have no knowledge of the facade and keep no reference to it.

2.2.5.4 Sample code In C# This structural code demonstrates the Facade pattern which provides a simplified and uniform interface to a large subsystem of classes. // Facade pattern -- Structural example using System; namespace DoFactory.GangOfFour.Facade.Structural { // Mainapp test application class MainApp { public static void Main() { Facade facade = new Facade(); facade.MethodA(); facade.MethodB(); // Wait for user Console.Read(); } } // "Subsystem ClassA" class SubSystemOne { public void MethodOne() { Console.WriteLine(" SubSystemOne Method"); } } // Subsystem ClassB" class SubSystemTwo { public void MethodTwo() { Console.WriteLine(" SubSystemTwo Method"); }

Version: 1.0 Side: 111

Project: Design Pattern } // Subsystem ClassC" class SubSystemThree { public void MethodThree() { Console.WriteLine(" SubSystemThree Method"); } } // Subsystem ClassD" class SubSystemFour { public void MethodFour() { Console.WriteLine(" SubSystemFour Method"); } } // "Facade" class Facade { SubSystemOne one; SubSystemTwo two; SubSystemThree three; SubSystemFour four; public Facade() { one = new SubSystemOne(); two = new SubSystemTwo(); three = new SubSystemThree(); four = new SubSystemFour(); } public void MethodA() { Console.WriteLine("\nMethodA() ---- "); one.MethodOne(); two.MethodTwo(); four.MethodFour(); } public void MethodB() { Console.WriteLine("\nMethodB() ---- "); two.MethodTwo(); three.MethodThree(); } } }

Version: 1.0 Side: 112

Project: Design Pattern

Output MethodA() ---SubSystemOne Method SubSystemTwo Method SubSystemFour Method MethodB() ---SubSystemTwo Method SubSystemThree Method

2.2.5.5 Sample code In ABAP This structural code demonstrates the Facade pattern which provides a simplified and uniform interface to a large subsystem of classes. *&---------------------------------------------------------------------* *& Report ZDP_FACADE_STRUCTURAL *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT

zdp_facade_structural.

*----------------------------------------------------------------------* * CLASS subsystemone DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS subsystemone DEFINITION. PUBLIC SECTION. METHODS: methodone. ENDCLASS. "subsystemone DEFINITION *----------------------------------------------------------------------* * CLASS subsystemone IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS subsystemone IMPLEMENTATION. METHOD methodone. WRITE: / 'SubsystemOne Method'. ENDMETHOD. "methodone ENDCLASS. "subsystemone IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS subsystemtwo DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS subsystemtwo DEFINITION. PUBLIC SECTION. METHODS: methodtwo. ENDCLASS. "subsystemtwo DEFINITION *----------------------------------------------------------------------* * CLASS subsystemtwo IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* Version: 1.0 Side: 113

Project: Design Pattern CLASS subsystemtwo IMPLEMENTATION. METHOD methodtwo. WRITE: / 'SubsystemTwo Method'. ENDMETHOD. "methodtwo ENDCLASS. "subsystemtwo IMPLEMENTATION *----------------------------------------------------------------------* * CLASS subsystemThree DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS subsystemthree DEFINITION. PUBLIC SECTION. METHODS: methodthree. ENDCLASS. "subsystemThree DEFINITION *----------------------------------------------------------------------* * CLASS subsystemthree IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS subsystemthree IMPLEMENTATION. METHOD methodthree. WRITE: / 'SubsystemThree Method'. ENDMETHOD. "methodthree ENDCLASS. "subsystemthree IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS subsystemfour DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS subsystemfour DEFINITION. PUBLIC SECTION. METHODS: methodfour. ENDCLASS. "subsystemfour DEFINITION *----------------------------------------------------------------------* * CLASS subsystemfour IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS subsystemfour IMPLEMENTATION. METHOD methodfour. WRITE: / 'SubsystemFour Method'. ENDMETHOD. "methodfour ENDCLASS. "subsystemfour IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS facade DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS facade DEFINITION. PUBLIC SECTION. DATA: one TYPE REF TO subsystemone ,two TYPE REF TO subsystemtwo ,three TYPE REF TO subsystemthree ,four TYPE REF TO subsystemfour . METHODS: constructor ,methoda Version: 1.0 Side: 114

Project: Design Pattern ,methodb . ENDCLASS. "facade DEFINITION *----------------------------------------------------------------------* * CLASS facade IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS facade IMPLEMENTATION. METHOD constructor. CREATE OBJECT one. CREATE OBJECT two. CREATE OBJECT three. CREATE OBJECT four. ENDMETHOD. "constructor METHOD methoda. WRITE: /, / 'MethodA() ----'. one->methodone( ). two->methodtwo( ). four->methodfour( ). ENDMETHOD. "methoda METHOD methodb. WRITE: /, / 'MethodB() ----'. two->methodtwo( ). three->methodthree( ). ENDMETHOD. "methodb ENDCLASS. "facade IMPLEMENTATION *----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp IMPLEMENTATION. METHOD main. DATA: facade TYPE REF TO facade. CREATE OBJECT facade. facade->methoda( ). facade->methodb( ). ENDMETHOD. ENDCLASS. START-OF-SELECTION. mainapp=>main( ). OUTPUT: --------MethodA() SubsystemOne Method SubsystemTwo Method SubsystemFour Method

Version: 1.0 Side: 115

"endmethod "mainapp IMPLEMENTATION

Project: Design Pattern MethodB() SubsystemTwo Method SubsystemThree Method

2.2.5.6 Sample code In C# This real-world code demonstrates the Facade pattern as a MortgageApplication object which provides a simplified interface to a large subsystem of classes measuring the creditworthyness of an applicant. // Facade pattern -- Real World example using System; namespace DoFactory.GangOfFour.Facade.RealWorld { // MainApp test application class MainApp { static void Main() { // Facade Mortgage mortgage = new Mortgage(); // Evaluate mortgage eligibility for customer Customer customer = new Customer("Ann McKinsey"); bool eligable = mortgage.IsEligible(customer,125000); Console.WriteLine("\n" + customer.Name + " has been " + (eligable ? "Approved" : "Rejected")); // Wait for user Console.Read(); } } // "Subsystem ClassA" class Bank { public bool HasSufficientSavings(Customer c, int amount) { Console.WriteLine("Check bank for " + c.Name); return true; } } // "Subsystem ClassB" class Credit { public bool HasGoodCredit(Customer c) Version: 1.0 Side: 116

Project: Design Pattern { Console.WriteLine("Check credit for " + c.Name); return true; } } // "Subsystem ClassC" class Loan { public bool HasNoBadLoans(Customer c) { Console.WriteLine("Check loans for " + c.Name); return true; } } class Customer { private string name; // Constructor public Customer(string name) { this.name = name; } // Property public string Name { get{ return name; } } } // "Facade" class Mortgage { private Bank bank = new Bank(); private Loan loan = new Loan(); private Credit credit = new Credit(); public bool IsEligible(Customer cust, int amount) { Console.WriteLine("{0} applies for {1:C} loan\n", cust.Name, amount); bool eligible = true; // Check creditworthyness of applicant if (!bank.HasSufficientSavings(cust, amount)) { eligible = false; } else if (!loan.HasNoBadLoans(cust)) { Version: 1.0 Side: 117

Project: Design Pattern eligible = false; } else if (!credit.HasGoodCredit(cust)) { eligible = false; } return eligible; } } }

Output Ann McKinsey applies for $125,000.00 loan Check bank for Ann McKinsey Check loans for Ann McKinsey Check credit for Ann McKinsey Ann McKinsey has been Approved

2.2.5.7 Sample code In ABAP This real-world code demonstrates the Facade pattern as a MortgageApplication object which provides a simplified interface to a large subsystem of classes measuring the creditworthyness of an applicant. *&---------------------------------------------------------------------* *& Report ZDP_FACADE_REALWORLD *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT

zdp_facade_realworld.

*----------------------------------------------------------------------* * CLASS customer DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS customer DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING name TYPE string ,getname RETURNING value(name) TYPE string . PRIVATE SECTION. DATA: name TYPE string. ENDCLASS. "customer DEFINITION *----------------------------------------------------------------------* * CLASS customer IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* Version: 1.0 Side: 118

Project: Design Pattern CLASS customer IMPLEMENTATION. METHOD constructor. me->name = name. ENDMETHOD. METHOD getname. name = me->name. ENDMETHOD. ENDCLASS.

"constructor

"getname "customer IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS bank DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS bank DEFINITION. PUBLIC SECTION. METHODS: hassufficientsavings IMPORTING customer TYPE REF TO customer amount TYPE i RETURNING value(val) TYPE boolean . ENDCLASS. "bank DEFINITION *----------------------------------------------------------------------* * CLASS bank IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS bank IMPLEMENTATION. METHOD hassufficientsavings. DATA: myname TYPE string. myname = customer->getname( ). WRITE: / 'Check bank for ', myname. val = 'X'. "~TRUE ENDMETHOD. "hassufficientsavings ENDCLASS. "bank IMPLEMENTATION *----------------------------------------------------------------------* * CLASS credit DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS credit DEFINITION. PUBLIC SECTION. METHODS: hasgoodcredit IMPORTING customer TYPE REF TO customer RETURNING value(value) TYPE boolean . ENDCLASS. "credit DEFINITION *----------------------------------------------------------------------* * CLASS credit IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS credit IMPLEMENTATION. METHOD hasgoodcredit. DATA: mycustomer TYPE string. mycustomer = customer->getname( ). WRITE: / 'Check credit for ', mycustomer. value = 'X'. "~true ENDMETHOD. "hasgoodcredit Version: 1.0 Side: 119

Project: Design Pattern ENDCLASS.

"credit IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS loan DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS loan DEFINITION. PUBLIC SECTION. METHODS: hasnobadloans IMPORTING customer TYPE REF TO customer RETURNING value(value) TYPE boolean. ENDCLASS. "loan DEFINITION *----------------------------------------------------------------------* * CLASS loan IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS loan IMPLEMENTATION. METHOD hasnobadloans. DATA: mycustomer TYPE string. mycustomer = customer->getname( ). WRITE: / 'Check loans for ', mycustomer. value = 'X'. "~true ENDMETHOD. "hasnobadloans ENDCLASS. "loan IMPLEMENTATION *----------------------------------------------------------------------* * CLASS mortgage DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mortgage DEFINITION. PUBLIC SECTION. METHODS: constructor ,iseligible IMPORTING customer TYPE REF TO customer amount TYPE i RETURNING value(value) TYPE boolean . PRIVATE SECTION. DATA: bank TYPE REF TO bank ,loan TYPE REF TO loan ,credit TYPE REF TO credit . ENDCLASS. "mortgage DEFINITION *----------------------------------------------------------------------* * CLASS mortgage IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mortgage IMPLEMENTATION. METHOD constructor. CREATE OBJECT bank. CREATE OBJECT loan. CREATE OBJECT credit. ENDMETHOD. "constructor METHOD iseligible. DATA: customername TYPE string. customername = customer->getname( ). Version: 1.0 Side: 120

Project: Design Pattern WRITE: / customername, ' applies for ', amount, 'loan '. value = 'X'. "~TRUE IF bank->hassufficientsavings( customer = customer amount = amount ) NE 'X'. value = '-'. " ~false ELSEIF loan->hasnobadloans( customer ) NE 'X'. value = '-'. "~false ELSEIF credit->hasgoodcredit( customer ) NE 'X'. value = '-'. "~false ENDIF. ENDMETHOD. ENDCLASS.

"iseligible "mortgage IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp IMPLEMENTATION. METHOD main. DATA: mortgage TYPE REF TO mortgage ,customer TYPE REF TO customer ,eligible TYPE boolean ,customername TYPE string . CREATE OBJECT mortgage. CREATE OBJECT customer EXPORTING name = 'Ann McKinsey'. eligible = mortgage->iseligible( customer = customer amount = 125000 ). customername = customer->getname( ). WRITE: /,/ customername, ' Has been '. IF eligible = 'X'. WRITE: ' Approved '. ELSE. WRITE: ' Rejected '. ENDIF. ENDMETHOD. ENDCLASS.

"endmethod "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ).

OUTPUT ------------Ann McKinsey applies for 125.000 Check bank for Ann McKinsey Check loans for Ann McKinsey Check credit for Ann McKinsey Ann McKinsey

Version: 1.0 Side: 121

Has been

Approved

loan

Project: Design Pattern

2.2.6 Flyweight (fluevægt) A fine-grained instance used for efficient sharing

2.2.6.1 Definition Use sharing to support large numbers of fine-grained (fin kornet) objects efficiently.

2.2.6.2 UML class diagram

2.2.6.3 Participants The classes and/or objects participating in this pattern are: • Flyweight (Character) o declares an interface through which flyweights can receive and act on extrinsic state. (udefra kommende/ydre) • ConcreteFlyweight (CharacterA, CharacterB, ..., CharacterZ) o implements the Flyweight interface and adds storage for intrinsic state, if any. A ConcreteFlyweight object must be sharable. Any state it stores must be intrinsic, (indre/indefra kommende) that is, it must be independent of the ConcreteFlyweight object's context. • UnsharedConcreteFlyweight ( not used ) o not all Flyweight subclasses need to be shared. The Flyweight interface enables sharing, but it doesn't enforce it. It is common for UnsharedConcreteFlyweight objects to have ConcreteFlyweight objects as children at some level in the flyweight object structure (as the Row and Column classes have). • FlyweightFactory (CharacterFactory) o creates and manages flyweight objects ensures that flyweight are shared properly. When a client requests a flyweight, the FlyweightFactory objects supplies an existing instance or creates one, if none exists. Version: 1.0 Side: 122

Project: Design Pattern •

Client (FlyweightApp) o maintains a reference to flyweight(s). computes or stores the extrinsic state of flyweight(s).

2.2.6.4 Sample code In C# This structural code demonstrates the Flyweight pattern in which a relatively small number of objects is shared many times by different clients. // Flyweight pattern -- Structural example using System; using System.Collections; namespace DoFactory.GangOfFour.Flyweight.Structural { // MainApp test application class MainApp { static void Main() { // Arbitrary extrinsic state int extrinsicstate = 22; FlyweightFactory f = new FlyweightFactory(); // Work with different flyweight instances Flyweight fx = f.GetFlyweight("X"); fx.Operation(--extrinsicstate); Flyweight fy = f.GetFlyweight("Y"); fy.Operation(--extrinsicstate); Flyweight fz = f.GetFlyweight("Z"); fz.Operation(--extrinsicstate); UnsharedConcreteFlyweight uf = new UnsharedConcreteFlyweight(); uf.Operation(--extrinsicstate); // Wait for user Console.Read(); } } // "FlyweightFactory" class FlyweightFactory { private Hashtable flyweights = new Hashtable(); // Constructor Version: 1.0 Side: 123

Project: Design Pattern public FlyweightFactory() { flyweights.Add("X", new ConcreteFlyweight()); flyweights.Add("Y", new ConcreteFlyweight()); flyweights.Add("Z", new ConcreteFlyweight()); } public Flyweight GetFlyweight(string key) { return((Flyweight)flyweights[key]); } } // "Flyweight" abstract class Flyweight { public abstract void Operation(int extrinsicstate); } // "ConcreteFlyweight" class ConcreteFlyweight : Flyweight { public override void Operation(int extrinsicstate) { Console.WriteLine("ConcreteFlyweight: " + extrinsicstate); } } // "UnsharedConcreteFlyweight" class UnsharedConcreteFlyweight : Flyweight { public override void Operation(int extrinsicstate) { Console.WriteLine("UnsharedConcreteFlyweight: " + extrinsicstate); } } }

Output ConcreteFlyweight: 21 ConcreteFlyweight: 20 ConcreteFlyweight: 19 UnsharedConcreteFlyweight: 18

2.2.6.5 Sample code In ABAP This structural code demonstrates the Flyweight pattern in which a relatively small number of objects is shared many times by different clients. *&---------------------------------------------------------------------* *& Report ZDP_FLYWEIGHT_STRUCTURAL *& Version: 1.0 Side: 124

Project: Design Pattern *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT

zdp_flyweight_structural.

*----------------------------------------------------------------------* * CLASS flyweight DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS flyweight DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: operation ABSTRACT IMPORTING extrincicstate TYPE i. ENDCLASS. "flyweight DEFINITION *----------------------------------------------------------------------* * CLASS concreteflyweight DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concreteflyweight DEFINITION INHERITING FROM flyweight. PUBLIC SECTION. METHODS: operation REDEFINITION. ENDCLASS. "concreteflyweight DEFINITION *----------------------------------------------------------------------* * CLASS concreteflyweight IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concreteflyweight IMPLEMENTATION. METHOD operation. WRITE: /5(20)'ConcreteFlyweight', extrincicstate. ENDMETHOD. "operation ENDCLASS. "concreteflyweight IMPLEMENTATION *----------------------------------------------------------------------* * CLASS unsharedconcreteflyweight DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS unsharedconcreteflyweight DEFINITION INHERITING FROM flyweight. PUBLIC SECTION. METHODS: operation REDEFINITION. ENDCLASS. "unsharedconcreteflyweight DEFINITION *----------------------------------------------------------------------* * CLASS unsharedconcreteflyweight IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS unsharedconcreteflyweight IMPLEMENTATION. METHOD operation. WRITE: /5(20)'UnsharedConcreteFlyweight', extrincicstate. ENDMETHOD. "operation ENDCLASS. "unsharedconcreteflyweight IMPLEMENTATION *----------------------------------------------------------------------* * CLASS flyweightfactory DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* Version: 1.0 Side: 125

Project: Design Pattern CLASS flyweightfactory DEFINITION. PUBLIC SECTION. TYPES: BEGIN OF ty_flyweight ,key(1) TYPE c ,value TYPE REF TO concreteflyweight ,END OF ty_flyweight. METHODS: constructor ,getflyweight IMPORTING key TYPE c RETURNING value(value) TYPE REF TO flyweight . PRIVATE SECTION. DATA flyweights TYPE HASHED TABLE OF ty_flyweight WITH UNIQUE KEY key. ENDCLASS. "flyweightfactory DEFINITION *----------------------------------------------------------------------* * CLASS flyweightfactory IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS flyweightfactory IMPLEMENTATION. METHOD constructor. DATA: cf TYPE REF TO concreteflyweight ,buffer TYPE ty_flyweight . CREATE OBJECT cf. buffer-key = 'X'. buffer-value = cf. INSERT buffer INTO TABLE flyweights. CREATE OBJECT cf. buffer-key = 'Y'. buffer-value = cf. INSERT buffer INTO TABLE flyweights. CREATE OBJECT cf. buffer-key = 'Z'. buffer-value = cf. INSERT buffer INTO TABLE flyweights. ENDMETHOD. "constructor METHOD getflyweight. DATA buffer TYPE ty_flyweight. READ TABLE flyweights WITH TABLE KEY key = key INTO buffer. value = buffer-value. ENDMETHOD. "getflyweight ENDCLASS. "flyweightfactory IMPLEMENTATION *----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp IMPLEMENTATION. METHOD main. Version: 1.0 Side: 126

Project: Design Pattern data: extrincicstate type i ,f type REF TO flyweightfactory ,fx TYPE REF TO flyweight ,fy TYPE REF TO flyweight ,fz TYPE REF TO flyweight ,uf TYPE REF TO unsharedconcreteflyweight . extrincicstate = 22. CREATE OBJECT f. fx = f->getflyweight( 'X' ). subtract 1 from extrincicstate. fx->operation( extrincicstate ). subtract 1 from extrincicstate. fy = f->getflyweight( 'Y' ). fy->operation( extrincicstate ). subtract 1 from extrincicstate. fz = f->getflyweight( 'Z' ). fz->operation( extrincicstate ). subtract 1 from extrincicstate. CREATE OBJECT uf. uf->operation( extrincicstate ). ENDMETHOD. ENDCLASS.

"endmethod "mainapp IMPLEMENTATION

START-OF-SELECTION. mainapp=>main( ). OUTPUT: -----------------

ConcreteFlyweight ConcreteFlyweight ConcreteFlyweight UnsharedConcreteFlyw

21 20 19 18

2.2.6.6 Sample code In C# This real-world code demonstrates the Flyweight pattern in which a relatively small number of Character objects is shared many times by a document that has potentially many characters. // Flyweight pattern -- Real World example using System; using System.Collections; namespace DoFactory.GangOfFour.Flyweight.RealWorld { // MainApp test application Version: 1.0 Side: 127

Project: Design Pattern

class MainApp { static void Main() { // Build a document with text string document = "AAZZBBZB"; char[] chars = document.ToCharArray(); CharacterFactory f = new CharacterFactory(); // extrinsic state int pointSize = 10; // For each character use a flyweight object foreach (char c in chars) { pointSize++; Character character = f.GetCharacter(c); character.Display(pointSize); } // Wait for user Console.Read(); } } // "FlyweightFactory" class CharacterFactory { private Hashtable characters = new Hashtable(); public Character GetCharacter(char key) { // Uses "lazy initialization" Character character = characters[key] as Character; if (character == null) { switch (key) { case 'A': character = new CharacterA(); break; case 'B': character = new CharacterB(); break; //... case 'Z': character = new CharacterZ(); break; } characters.Add(key, character); } return character; } } // "Flyweight" abstract class Character { Version: 1.0 Side: 128

Project: Design Pattern protected protected protected protected protected protected

char symbol; int width; int height; int ascent; int descent; int pointSize;

public abstract void Display(int pointSize); } // "ConcreteFlyweight" class CharacterA : Character { // Constructor public CharacterA() { this.symbol = 'A'; this.height = 100; this.width = 120; this.ascent = 70; this.descent = 0; } public override void Display(int pointSize) { this.pointSize = pointSize; Console.WriteLine(this.symbol + " (pointsize " + this.pointSize + ")"); } } // "ConcreteFlyweight" class CharacterB : Character { // Constructor public CharacterB() { this.symbol = 'B'; this.height = 100; this.width = 140; this.ascent = 72; this.descent = 0; } public override void Display(int pointSize) { this.pointSize = pointSize; Console.WriteLine(this.symbol + " (pointsize " + this.pointSize + ")"); } } // ... C, D, E, etc. Version: 1.0 Side: 129

Project: Design Pattern

// "ConcreteFlyweight" class CharacterZ : Character { // Constructor public CharacterZ() { this.symbol = 'Z'; this.height = 100; this.width = 100; this.ascent = 68; this.descent = 0; } public override void Display(int pointSize) { this.pointSize = pointSize; Console.WriteLine(this.symbol + " (pointsize " + this.pointSize + ")"); } } }

Output A A Z Z B B Z B

(pointsize (pointsize (pointsize (pointsize (pointsize (pointsize (pointsize (pointsize

11) 12) 13) 14) 15) 16) 17) 18)

2.2.7 Proxy An object representing another object

2.2.7.1 Definition Provide a surrogate or placeholder for another object to control access to it.

Version: 1.0 Side: 130

Project: Design Pattern

2.2.7.2 UML class diagram

2.2.7.3 Participants The classes and/or objects participating in this pattern are: • Proxy (MathProxy) o maintains a reference that lets the proxy access the real subject. Proxy may refer to a Subject if the RealSubject and Subject interfaces are the same. provides an interface identical to Subject's so that a proxy can be substituted for for the real subject. controls access to the real subject and may be responsible for creating and deleting it. other responsibilites depend on the kind of proxy: ƒ remote proxies are responsible for encoding a request and its arguments and for sending the encoded request to the real subject in a different address space. ƒ virtual proxies may cache additional information about the real subject so that they can postpone accessing it. For example, the ImageProxy from the Motivation caches the real images's extent. ƒ protection proxies check that the caller has the access permissions required to perform a request. • Subject (IMath) o defines the common interface for RealSubject and Proxy so that a Proxy can be used anywhere a RealSubject is expected. • RealSubject (Math) o defines the real object that the proxy represents.

2.2.7.4 Sample code In C# This structural code demonstrates the Proxy pattern which provides a representative object (proxy) that controls access to another similar object. // Proxy pattern -- Structural example

Version: 1.0 Side: 131

Project: Design Pattern using System; namespace DoFactory.GangOfFour.Proxy.Structural { // MainApp test application class MainApp { static void Main() { // Create proxy and request a service Proxy proxy = new Proxy(); proxy.Request(); // Wait for user Console.Read(); } } // "Subject" abstract class Subject { public abstract void Request(); } // "RealSubject" class RealSubject : Subject { public override void Request() { Console.WriteLine("Called RealSubject.Request()"); } } // "Proxy" class Proxy : Subject { RealSubject realSubject; public override void Request() { // Use 'lazy initialization' if (realSubject == null) { realSubject = new RealSubject(); } realSubject.Request(); } } }

Version: 1.0 Side: 132

Project: Design Pattern

Output Called RealSubject.Request()

2.2.7.5 Sample code In ABAP *&---------------------------------------------------------------------* *& Report ZDP_PROXY_STRUCTURAL *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT

zdp_proxy_structural.

*----------------------------------------------------------------------* * CLASS subject DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS subject DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: request ABSTRACT. ENDCLASS. "subject DEFINITION *----------------------------------------------------------------------* * CLASS realsubject DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS realsubject DEFINITION INHERITING FROM subject. PUBLIC SECTION. METHODS: request REDEFINITION. ENDCLASS. "realsubject DEFINITION *----------------------------------------------------------------------* * CLASS realsubject IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS realsubject IMPLEMENTATION. METHOD request. WRITE: / 'Called RealSubject.Request()'. ENDMETHOD. "request ENDCLASS. "realsubject IMPLEMENTATION *----------------------------------------------------------------------* * CLASS proxy DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS proxy DEFINITION INHERITING FROM subject. PUBLIC SECTION. DATA: realsubject TYPE REF TO realsubject. METHODS: Version: 1.0 Side: 133

Project: Design Pattern request REDEFINITION. ENDCLASS. "proxy DEFINITION *----------------------------------------------------------------------* * CLASS proxy IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS proxy IMPLEMENTATION. METHOD request. * use lazy initialization IF me->realsubject IS INITIAL. CREATE OBJECT realsubject. ENDIF. me->realsubject->request( ). ENDMETHOD. "request ENDCLASS. "proxy IMPLEMENTATION *---------------------------------------------------------* CLASS lcl_application DEFINITION *---------------------------------------------------------CLASS lcl_application DEFINITION CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS: run. METHODS: constructor. PRIVATE SECTION. CLASS-DATA: so_application TYPE REF TO lcl_application. ENDCLASS. "lcl_application DEFINITION *---------------------------------------------------------* IMPLEMENTATION *---------------------------------------------------------CLASS lcl_application IMPLEMENTATION. *---------------------------------------------------------* LCL_APPLICATION->RUN(). *---------------------------------------------------------METHOD run. DATA: exc_ref TYPE REF TO cx_root ,exc_text TYPE string. IF lcl_application=>so_application IS INITIAL. TRY. CREATE OBJECT lcl_application=>so_application. CATCH cx_sy_create_object_error INTO exc_ref. exc_text = exc_ref->get_text( ). MESSAGE exc_text TYPE 'I'. ENDTRY. ENDIF. ENDMETHOD. "run *---------------------------------------------------------* LCL_APPLICATION->CONSTRUCTOR(). * Use the constructor for instantiating internal objects, * fields, tables and events. *---------------------------------------------------------METHOD constructor. DATA: proxy TYPE REF TO proxy. CREATE OBJECT proxy.

Version: 1.0 Side: 134

Project: Design Pattern proxy->request( ). ENDMETHOD.

"constructor

ENDCLASS.

"lcl_application IMPLEMENTATION

START-OF-SELECTION. lcl_application=>run( ). Output: Program ZDP_PROXY_STRUCTURAL Called RealSubject.Request()

2.2.7.6 Sample code In C# This real-world code demonstrates the Proxy pattern for a Math object represented by a MathProxy object. // Proxy pattern -- Real World example using System; namespace DoFactory.GangOfFour.Proxy.RealWorld { // Mainapp test application class MainApp { static void Main() { // Create math proxy MathProxy p = new MathProxy(); // Do the math Console.WriteLine("4 Console.WriteLine("4 Console.WriteLine("4 Console.WriteLine("4

+ * /

2 2 2 2

= = = =

" " " "

// Wait for user Console.Read(); } } // "Subject" public interface IMath { double Add(double x, double y); double Sub(double x, double y); double Mul(double x, double y);

Version: 1.0 Side: 135

+ + + +

p.Add(4, p.Sub(4, p.Mul(4, p.Div(4,

2)); 2)); 2)); 2));

Project: Design Pattern double Div(double x, double y); } // "RealSubject" class Math : IMath { public double Add(double public double Sub(double public double Mul(double public double Div(double }

x, x, x, x,

double double double double

y){return y){return y){return y){return

x x x x

+ * /

y;} y;} y;} y;}

// "Proxy Object" class MathProxy : IMath { Math math; public MathProxy() { math = new Math(); } public double Add(double { return math.Add(x,y); } public double Sub(double { return math.Sub(x,y); } public double Mul(double { return math.Mul(x,y); } public double Div(double { return math.Div(x,y); }

x, double y)

x, double y)

x, double y)

x, double y)

} }

Output 4 4 4 4

+ * /

2 2 2 2

= = = =

6 2 8 2

2.2.7.7 Sample code In ABAP using interface This real-world code demonstrates the Proxy pattern for a Math object represented by a MathProxy object. *&---------------------------------------------------------------------* *& Report ZDP_PROXY_REALWORLD Version: 1.0 Side: 136

Project: Design Pattern *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT

zdp_proxy_realworld.

*----------------------------------------------------------------------* * INTERFACE if_math *----------------------------------------------------------------------* * *----------------------------------------------------------------------* INTERFACE if_math. METHODS: add IMPORTING x TYPE i y TYPE i RETURNING value(v) TYPE i ,sub IMPORTING x TYPE i y TYPE i RETURNING value(v) TYPE i ,mul IMPORTING x TYPE i y TYPE i RETURNING value(v) TYPE i ,div IMPORTING x TYPE i y TYPE i RETURNING value(v) TYPE i . ENDINTERFACE. "if_math *----------------------------------------------------------------------* * CLASS math DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS math DEFINITION. PUBLIC SECTION. INTERFACES: if_math. ALIASES: add FOR if_math~add ,sub FOR if_math~sub ,mul FOR if_math~mul ,div FOR if_math~div. ENDCLASS. "math DEFINITION *----------------------------------------------------------------------* * CLASS math IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS math IMPLEMENTATION. METHOD add. v = x + y. ENDMETHOD. "add METHOD sub. v = x - y. ENDMETHOD. "sub METHOD mul. v = x * y. ENDMETHOD. "mul METHOD div. v = x DIV y. ENDMETHOD. "div ENDCLASS. "math IMPLEMENTATION *----------------------------------------------------------------------* * CLASS mathproxy DEFINITION

Version: 1.0 Side: 137

Project: Design Pattern *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mathproxy DEFINITION. PUBLIC SECTION. DATA: math TYPE REF TO math. INTERFACES: if_math. ALIASES: add FOR if_math~add ,sub FOR if_math~sub ,mul FOR if_math~mul ,div FOR if_math~div. METHODS: constructor. ENDCLASS. "mathproxy DEFINITION *----------------------------------------------------------------------* * CLASS mathproxy IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mathproxy IMPLEMENTATION. METHOD constructor. CREATE OBJECT math. ENDMETHOD. "constructor METHOD add. v = math->add( x = x y = y ). ENDMETHOD. "add METHOD sub. v = math->sub( x = x y = y ). ENDMETHOD. "sub METHOD mul. v = math->mul( x = x y = y ). ENDMETHOD. "mul METHOD div. v = math->div( x = x y = y ). ENDMETHOD. "div ENDCLASS. "mathproxy IMPLEMENTATION *----------------------------------------------------------------------* *---------------------------------------------------------* CLASS lcl_application DEFINITION *---------------------------------------------------------CLASS lcl_application DEFINITION CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS: run. METHODS: constructor. PRIVATE SECTION. CLASS-DATA: so_application TYPE REF TO lcl_application. ENDCLASS. "lcl_application DEFINITION *---------------------------------------------------------* IMPLEMENTATION *---------------------------------------------------------CLASS lcl_application IMPLEMENTATION. *---------------------------------------------------------* LCL_APPLICATION->RUN().

Version: 1.0 Side: 138

Project: Design Pattern *---------------------------------------------------------METHOD run. DATA: exc_ref TYPE REF TO cx_root ,exc_text TYPE string. IF lcl_application=>so_application IS INITIAL. TRY. CREATE OBJECT lcl_application=>so_application. CATCH cx_sy_create_object_error INTO exc_ref. exc_text = exc_ref->get_text( ). MESSAGE exc_text TYPE 'I'. ENDTRY. ENDIF. ENDMETHOD. "run *---------------------------------------------------------* LCL_APPLICATION->CONSTRUCTOR(). * Use the constructor for instantiating internal objects, * fields, tables and events. *---------------------------------------------------------METHOD constructor. DATA: p TYPE REF TO mathproxy ,result TYPE i . CREATE OBJECT p. *

do the math result = p->add( x = 4 y = 2 ). WRITE:/ '4 + 2 = ', result. result = p->sub( x = 4 y = 2 ). WRITE:/ '4 - 2 = ', result. result = p->mul( x = 4 y = 2 ). WRITE:/ '4 * 2 = ', result. result = p->div( x = 4 y = 2 ). WRITE:/ '4 / 2 = ', result. ENDMETHOD. "constructor

ENDCLASS.

"lcl_application IMPLEMENTATION

START-OF-SELECTION. lcl_application=>run( ).

2.3 Behavioral Patterns 2.3.1 Chain of Resp. A way of passing a request between a chain of objects

2.3.1.1 Definition Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass

Version: 1.0 Side: 139

Project: Design Pattern the request along the chain until an object handles it. The client do know which of the receiver that are the first I the chain.

2.3.1.2 UML class diagram

2.3.1.3 Participants The classes and/or objects participating in this pattern are: • Handler (Approver) o defines an interface for handling the requests (optional) implements the successor link • ConcreteHandler (Director, VicePresident, President) o handles requests it is responsible for can access its successor if the ConcreteHandler can handle the request, it does so; otherwise it forwards the request to its successor • Client (ChainApp) o initiates the request to a ConcreteHandler object on the chain

2.3.1.4 Sample code In C# This structural code demonstrates the Chain of Responsibility pattern in which several linked objects (the Chain) are offered the opportunity to respond to a request or hand it off to the object next in line. // Chain of Responsibility pattern -- Structural example using System; namespace DoFactory.GangOfFour.Chain.Structural { // MainApp test application class MainApp { static void Main() { // Setup Chain of Responsibility Handler h1 = new ConcreteHandler1(); Handler h2 = new ConcreteHandler2(); Handler h3 = new ConcreteHandler3();

Version: 1.0 Side: 140

Project: Design Pattern h1.SetSuccessor(h2); h2.SetSuccessor(h3); // Generate and process request int[] requests = {2, 5, 14, 22, 18, 3, 27, 20}; foreach (int request in requests) { h1.HandleRequest(request); } // Wait for user Console.Read(); } } // "Handler" abstract class Handler { protected Handler successor; public void SetSuccessor(Handler successor) { this.successor = successor; } public abstract void HandleRequest(int request); }

class ConcreteHandler1 : Handler { public override void HandleRequest(int request) { if (request >= 0 && request < 10) { Console.WriteLine("{0} handled request {1}", this.GetType().Name, request); } else if (successor != null) { successor.HandleRequest(request); } } } // "ConcreteHandler2" class ConcreteHandler2 : Handler { public override void HandleRequest(int request) { if (request >= 10 && request < 20) { Version: 1.0 Side: 141

Project: Design Pattern Console.WriteLine("{0} handled request {1}", this.GetType().Name, request); } else if (successor != null) { successor.HandleRequest(request); } } } // "ConcreteHandler3" class ConcreteHandler3 : Handler { public override void HandleRequest(int request) { if (request >= 20 && request < 30) { Console.WriteLine("{0} handled request {1}", this.GetType().Name, request); } else if (successor != null) { successor.HandleRequest(request); } } } }

Output ConcreteHandler1 ConcreteHandler1 ConcreteHandler2 ConcreteHandler3 ConcreteHandler2 ConcreteHandler1 ConcreteHandler3 ConcreteHandler3

handled handled handled handled handled handled handled handled

request request request request request request request request

2 5 14 22 18 3 27 20

2.3.1.5 Sample code In ABAP This structural code demonstrates the Chain of Responsibility pattern in which several linked objects (the Chain) are offered the opportunity to respond to a request or hand it off to the object next in line. *&---------------------------------------------------------------------* *& Report ZDP_CHAINOFRESP_STRUCTURAL *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT zdp_chainofresp_structural. CLASS cl_abap_typedescr DEFINITION LOAD.

Version: 1.0 Side: 142

Project: Design Pattern *----------------------------------------------------------------------* * Global Data *----------------------------------------------------------------------* DATA: moff TYPE i ,slen TYPE i ,mlen TYPE i. *----------------------------------------------------------------------* * Macro ?get_class_name returns the class name of the class * Importing &1 Any Class * Exporting &2 The name of the Class &1 *----------------------------------------------------------------------* DEFINE ?get_class_name. &2 = cl_abap_classdescr=>get_class_name( &1 ). find regex 'CLASS=' in &2 match offset moff match length mlen. slen = moff + mlen. shift &2 by slen places left. END-OF-DEFINITION. *----------------------------------------------------------------------* * CLASS handler DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS handler DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: setsuccessor IMPORTING successor TYPE REF TO handler ,handlerequest ABSTRACT IMPORTING request TYPE i . PROTECTED SECTION. DATA: successor TYPE REF TO handler. ENDCLASS. "handler DEFINITION *----------------------------------------------------------------------* * CLASS handler IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS handler IMPLEMENTATION. METHOD setsuccessor. me->successor = successor. ENDMETHOD. "setsuccessor ENDCLASS. "handler IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS concretehandler1 DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concretehandler1 DEFINITION INHERITING FROM handler. PUBLIC SECTION. METHODS: handlerequest REDEFINITION. ENDCLASS. "concretehandler1 DEFINITION *----------------------------------------------------------------------* * CLASS concretehandler1 IMPLEMENTATION

Version: 1.0 Side: 143

Project: Design Pattern *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concretehandler1 IMPLEMENTATION. METHOD handlerequest. DATA: class_name TYPE abap_abstypename. ?get_class_name me class_name. IF ( request >= 0 AND request < 10 ). WRITE: / class_name, 'Handled request', request. ELSEIF ( NOT successor IS INITIAL ). me->successor->handlerequest( request ). ENDIF. ENDMETHOD. "handlerequest ENDCLASS. "concretehandler1 IMPLEMENTATION *----------------------------------------------------------------------* * CLASS concretehandler2 DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concretehandler2 DEFINITION INHERITING FROM handler. PUBLIC SECTION. METHODS: handlerequest REDEFINITION. ENDCLASS. "concretehandler2 DEFINITION *----------------------------------------------------------------------* * CLASS concretehandler2 IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concretehandler2 IMPLEMENTATION. METHOD handlerequest. DATA: class_name TYPE abap_abstypename. ?get_class_name me class_name. IF ( request >= 10 AND request < 20 ). WRITE: / class_name, 'Handled request', request. ELSEIF ( NOT successor IS INITIAL ). me->successor->handlerequest( request ). ENDIF. ENDMETHOD. "handlerequest ENDCLASS. "concretehandler2 IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS concretehandler3 DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concretehandler3 DEFINITION INHERITING FROM handler. PUBLIC SECTION. METHODS: handlerequest REDEFINITION. ENDCLASS. "concretehandler3 DEFINITION *----------------------------------------------------------------------* * CLASS concretehandler3 IMPLEMENTATION *----------------------------------------------------------------------* *

Version: 1.0 Side: 144

Project: Design Pattern *----------------------------------------------------------------------* CLASS concretehandler3 IMPLEMENTATION. METHOD handlerequest. DATA: class_name TYPE abap_abstypename. ?get_class_name me class_name. IF ( request >= 20 AND request < 30 ). WRITE: / class_name, 'Handled request', request. ELSEIF ( NOT successor IS INITIAL ). me->successor->handlerequest( request ). ENDIF. ENDMETHOD. "handlerequest ENDCLASS. "concretehandler3 IMPLEMENTATION

*---------------------------------------------------------* CLASS lcl_application DEFINITION *---------------------------------------------------------CLASS lcl_application DEFINITION CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS: run. METHODS: constructor. PRIVATE SECTION. CLASS-DATA: so_application TYPE REF TO lcl_application. ENDCLASS. "lcl_application DEFINITION *---------------------------------------------------------* IMPLEMENTATION *---------------------------------------------------------CLASS lcl_application IMPLEMENTATION. *---------------------------------------------------------* LCL_APPLICATION->RUN(). *---------------------------------------------------------METHOD run. DATA: exc_ref TYPE REF TO cx_root ,exc_text TYPE string. IF lcl_application=>so_application IS INITIAL. TRY. CREATE OBJECT lcl_application=>so_application. CATCH cx_sy_create_object_error INTO exc_ref. exc_text = exc_ref->get_text( ). MESSAGE exc_text TYPE 'I'. ENDTRY. ENDIF. ENDMETHOD. "run *---------------------------------------------------------* LCL_APPLICATION->CONSTRUCTOR(). * Use the constructor for instantiating internal objects, * fields, tables and events. *---------------------------------------------------------METHOD constructor. DATA: h1 TYPE REF TO concretehandler1 ,h2 TYPE REF TO concretehandler2 ,h3 TYPE REF TO concretehandler3

Version: 1.0 Side: 145

Project: Design Pattern ,t_request TYPE TABLE OF i ,request TYPE i . *

create CREATE CREATE CREATE

objects OBJECT h1. OBJECT h2. OBJECT h3.

h1->setsuccessor( h2 ). h2->setsuccessor( h3 ). INSERT INSERT INSERT INSERT INSERT INSERT INSERT INSERT

2 5 14 22 18 3 27 20

INTO INTO INTO INTO INTO INTO INTO INTO

TABLE TABLE TABLE TABLE TABLE TABLE TABLE TABLE

t_request. t_request. t_request. t_request. t_request. t_request. t_request. t_request.

LOOP AT t_request INTO request. h1->handlerequest( request ). ENDLOOP. ENDMETHOD. ENDCLASS.

"constructor "lcl_application IMPLEMENTATION

START-OF-SELECTION. lcl_application=>run( ).

2.3.1.6 Sample code In C# This real-world code demonstrates the Chain of Responsibility pattern in which several linked managers and executives can respond to a purchase request or hand it off to a superior. Each position has can have its own set of rules which orders they can approve. // Chain of Responsibility pattern -- Real World example using System; namespace DoFactory.GangOfFour.Chain.RealWorld { // MainApp test application class MainApp { static void Main() { // Setup Chain of Responsibility Director Larry = new Director(); VicePresident Sam = new VicePresident(); President Tammy = new President(); Larry.SetSuccessor(Sam); Version: 1.0 Side: 146

Project: Design Pattern Sam.SetSuccessor(Tammy); // Generate and process purchase requests Purchase p = new Purchase(2034, 350.00, "Supplies"); Larry.ProcessRequest(p); p = new Purchase(2035, 32590.10, "Project X"); Larry.ProcessRequest(p); p = new Purchase(2036, 122100.00, "Project Y"); Larry.ProcessRequest(p); // Wait for user Console.Read(); } } // "Handler" abstract class Approver { protected Approver successor; public void SetSuccessor(Approver successor) { this.successor = successor; } public abstract void ProcessRequest(Purchase purchase); } // "ConcreteHandler" class Director : Approver { public override void ProcessRequest(Purchase purchase) { if (purchase.Amount < 10000.0) { Console.WriteLine("{0} approved request# {1}", this.GetType().Name, purchase.Number); } else if (successor != null) { successor.ProcessRequest(purchase); } } } // "ConcreteHandler" class VicePresident : Approver { public override void ProcessRequest(Purchase purchase) { if (purchase.Amount < 25000.0) Version: 1.0 Side: 147

Project: Design Pattern { Console.WriteLine("{0} approved request# {1}", this.GetType().Name, purchase.Number); } else if (successor != null) { successor.ProcessRequest(purchase); } } } // "ConcreteHandler" class President : Approver { public override void ProcessRequest(Purchase purchase) { if (purchase.Amount < 100000.0) { Console.WriteLine("{0} approved request# {1}", this.GetType().Name, purchase.Number); } else { Console.WriteLine( "Request# {0} requires an executive meeting!", purchase.Number); } } } // Request details class Purchase { private int number; private double amount; private string purpose; // Constructor public Purchase(int number, double amount, string purpose) { this.number = number; this.amount = amount; this.purpose = purpose; } // Properties public double Amount { get{ return amount; } set{ amount = value; } } public string Purpose { Version: 1.0 Side: 148

Project: Design Pattern get{ return purpose; } set{ purpose = value; } } public int Number { get{ return number; } set{ number = value; } } } }

Output Director Larry approved request# 2034 President Tammy approved request# 2035 Request# 2036 requires an executive meeting!

2.3.1.7 Sample code In ABAP This real-world code demonstrates the Chain of Responsibility pattern in which several linked managers and executives can respond to a purchase request or hand it off to a superior. Each position has can have its own set of rules which orders they can approve. *&---------------------------------------------------------------------* *& Report ZDP_CHAINOFRESP_REALWORLD *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT zdp_chainofresp_realworld. CLASS cl_abap_typedescr DEFINITION LOAD. *----------------------------------------------------------------------* * Global Data *----------------------------------------------------------------------* DATA: moff TYPE i ,slen TYPE i ,mlen TYPE i. *----------------------------------------------------------------------* * Macro ?get_class_name returns the class name of the class * Importing &1 Any Class * Exporting &2 The name of the Class &1 *----------------------------------------------------------------------* DEFINE ?get_class_name. &2 = cl_abap_classdescr=>get_class_name( &1 ). find regex 'CLASS=' in &2 match offset moff match length mlen. slen = moff + mlen. shift &2 by slen places left. END-OF-DEFINITION. *----------------------------------------------------------------------* * CLASS purchase DEFINITION *----------------------------------------------------------------------* Version: 1.0 Side: 149

Project: Design Pattern * *----------------------------------------------------------------------* CLASS purchase DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING number TYPE i amount TYPE f purpose TYPE string ,get_property IMPORTING name TYPE string RETURNING value(dref) TYPE REF TO data. PRIVATE SECTION. DATA: number TYPE i ,amount TYPE f ,purpose TYPE string . ENDCLASS. "purchase DEFINITION *----------------------------------------------------------------------* * CLASS purchase IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS purchase IMPLEMENTATION. METHOD constructor. me->number = number. me->amount = amount. me->purpose = purpose. ENDMETHOD. "constructor METHOD get_property. CASE name. WHEN 'NUMBER'. GET REFERENCE OF me->number INTO dref. WHEN 'AMOUNT'. GET REFERENCE OF me->amount INTO dref. WHEN 'PURPOSE'. GET REFERENCE OF me->purpose INTO dref. ENDCASE. ENDMETHOD. "get_property ENDCLASS.

"purchase IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS approver DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS approver DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: constructor IMPORTING name TYPE string ,setsuccessor IMPORTING successor TYPE REF TO approver ,processrequest ABSTRACT IMPORTING purchase TYPE REF TO purchase . PROTECTED SECTION. DATA: name TYPE string. DATA: successor TYPE REF TO approver. ENDCLASS. "approver DEFINITION *----------------------------------------------------------------------*

Version: 1.0 Side: 150

Project: Design Pattern * CLASS approver IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS approver IMPLEMENTATION. METHOD constructor. me->name = name. ENDMETHOD. "constructor METHOD setsuccessor. me->successor = successor. ENDMETHOD. "SetSuccessor ENDCLASS. "approver IMPLEMENTATION *----------------------------------------------------------------------* * CLASS Director DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS director DEFINITION INHERITING FROM approver. PUBLIC SECTION. METHODS: processrequest REDEFINITION. ENDCLASS. "Director DEFINITION *----------------------------------------------------------------------* * CLASS Director IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS director IMPLEMENTATION. METHOD processrequest. FIELD-SYMBOLS: TYPE f , TYPE i. DATA: class_name TYPE abap_abstypename ,lv_dref TYPE REF TO data. ?get_class_name me class_name. lv_dref = purchase->get_property( 'AMOUNT' ). ASSIGN lv_dref->* TO . lv_dref = purchase->get_property( 'NUMBER' ). ASSIGN lv_dref->* TO . IF < 10000. WRITE: / class_name, me>name, 'Approved request', USING EDIT MASK '____' . ELSE. IF NOT me->successor IS INITIAL. me->successor->processrequest( purchase ). ENDIF. ENDIF. ENDMETHOD. "ProcessRequest ENDCLASS. "Director IMPLEMENTATION *----------------------------------------------------------------------* * CLASS VicePresident DEFINITION *----------------------------------------------------------------------*

Version: 1.0 Side: 151

Project: Design Pattern * *----------------------------------------------------------------------* CLASS vicepresident DEFINITION INHERITING FROM approver. PUBLIC SECTION. METHODS: processrequest REDEFINITION. ENDCLASS. "VicePresident DEFINITION *----------------------------------------------------------------------* * CLASS VicePresident IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS vicepresident IMPLEMENTATION. METHOD processrequest. FIELD-SYMBOLS: TYPE f , TYPE i. DATA: class_name TYPE abap_abstypename ,lv_dref TYPE REF TO data. ?get_class_name me class_name. lv_dref = purchase->get_property( 'AMOUNT' ). ASSIGN lv_dref->* TO . lv_dref = purchase->get_property( 'NUMBER' ). ASSIGN lv_dref->* TO . IF < 25000. WRITE: / class_name, me>name, 'Approved request', USING EDIT MASK '____'. ELSE. IF NOT me->successor IS INITIAL. me->successor->processrequest( purchase ). ENDIF. ENDIF. ENDMETHOD. "ProcessRequest ENDCLASS. "VicePresident IMPLEMENTATION *----------------------------------------------------------------------* * CLASS President DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS president DEFINITION INHERITING FROM approver. PUBLIC SECTION. METHODS: processrequest REDEFINITION. ENDCLASS. "President DEFINITION *----------------------------------------------------------------------* * CLASS President IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS president IMPLEMENTATION. METHOD processrequest. FIELD-SYMBOLS: TYPE f

Version: 1.0 Side: 152

Project: Design Pattern , TYPE i. DATA: class_name TYPE abap_abstypename ,lv_dref TYPE REF TO data. ?get_class_name me class_name. lv_dref = purchase->get_property( 'AMOUNT' ). ASSIGN lv_dref->* TO . lv_dref = purchase->get_property( 'NUMBER' ). ASSIGN lv_dref->* TO . IF < 100000. WRITE: / class_name, me>name, 'Approved request', USING EDIT MASK '____'. ELSE. WRITE: / class_name, me>name, 'Requires an executive meeting', USING EDIT MASK '____'. ENDIF. ENDMETHOD. "ProcessRequest ENDCLASS. "President IMPLEMENTATION *---------------------------------------------------------* CLASS lcl_application DEFINITION *---------------------------------------------------------CLASS lcl_application DEFINITION CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS: run. METHODS: constructor. PRIVATE SECTION. CLASS-DATA: so_application TYPE REF TO lcl_application. ENDCLASS. "lcl_application DEFINITION *---------------------------------------------------------* IMPLEMENTATION *---------------------------------------------------------CLASS lcl_application IMPLEMENTATION. *---------------------------------------------------------* LCL_APPLICATION->RUN(). *---------------------------------------------------------METHOD run. DATA: exc_ref TYPE REF TO cx_root ,exc_text TYPE string. IF lcl_application=>so_application IS INITIAL. TRY. CREATE OBJECT lcl_application=>so_application. CATCH cx_sy_create_object_error INTO exc_ref. exc_text = exc_ref->get_text( ). MESSAGE exc_text TYPE 'I'. ENDTRY. ENDIF. ENDMETHOD. "run *---------------------------------------------------------* LCL_APPLICATION->CONSTRUCTOR().

Version: 1.0 Side: 153

Project: Design Pattern * Use the constructor for instantiating internal objects, * fields, tables and events. *---------------------------------------------------------METHOD constructor. DATA: larry TYPE REF TO director ,sam TYPE REF TO vicepresident ,tammy TYPE REF TO president ,p TYPE REF TO purchase . BREAK-POINT. CREATE OBJECT larry EXPORTING name = 'Larry' . CREATE OBJECT sam EXPORTING name = 'Sam'. CREATE OBJECT tammy EXPORTING name = 'Tammy'. larry->setsuccessor( sam ). sam->setsuccessor( tammy ). CREATE OBJECT p EXPORTING number = 2034 amount = 350 purpose = 'Supplies'. larry->processrequest( p ). CREATE OBJECT p EXPORTING number = 2035 amount = '32590.10' purpose = 'Project X'. larry->processrequest( p ). CREATE OBJECT p EXPORTING number = 2036 amount = '122100.00' purpose = 'Project Y'. larry->processrequest( p ). ENDMETHOD. ENDCLASS.

"constructor "lcl_application IMPLEMENTATION

START-OF-SELECTION. lcl_application=>run( ).

2.3.2 Command Encapsulate a command request as an object

2.3.2.1 Definition Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

Version: 1.0 Side: 154

Project: Design Pattern

2.3.2.2 UML class diagram

2.3.2.3 Participants The classes and/or objects participating in this pattern are: • •

• • •

Command (Command) o declares an interface for executing an operation ConcreteCommand (CalculatorCommand) o defines a binding between a Receiver object and an action o implements Execute by invoking the corresponding operation(s) on Receiver Client (CommandApp) o creates a ConcreteCommand object and sets its receiver Invoker (User) o asks the command to carry out the request Receiver (Calculator) o knows how to perform the operations associated with carrying out the request.

2.3.2.4 Sample code In C# This structural code demonstrates the Command pattern which stores requests as objects allowing clients to execute or playback the requests. // Command pattern -- Structural example using System; namespace DoFactory.GangOfFour.Command.Structural { // MainApp test applicatio class MainApp { static void Main()

Version: 1.0 Side: 155

Project: Design Pattern { // Create receiver, command, and invoker Receiver receiver = new Receiver(); Command command = new ConcreteCommand(receiver); Invoker invoker = new Invoker(); // Set and execute command invoker.SetCommand(command); invoker.ExecuteCommand(); // Wait for user Console.Read(); } } // "Command" abstract class Command { protected Receiver receiver; // Constructor public Command(Receiver receiver) { this.receiver = receiver; } public abstract void Execute(); } // "ConcreteCommand" class ConcreteCommand : Command { // Constructor public ConcreteCommand(Receiver receiver) : base(receiver) { } public override void Execute() { receiver.Action(); } } // "Receiver" class Receiver { public void Action() { Console.WriteLine("Called Receiver.Action()"); } }

Version: 1.0 Side: 156

Project: Design Pattern // "Invoker" class Invoker { private Command command; public void SetCommand(Command command) { this.command = command; } public void ExecuteCommand() { command.Execute(); } } }

Output Called Receiver.Action()

2.3.2.5 Sample code in ABAP This structural code demonstrates the Command pattern which stores requests as objects allowing clients to execute or playback the requests. *&---------------------------------------------------------------------* *& Report ZDP_COMMAND_STRUCTURAL *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT

zdp_command_structural.

*----------------------------------------------------------------------* * CLASS receiver DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS receiver DEFINITION. PUBLIC SECTION. METHODS: action. ENDCLASS. "receiver DEFINITION *----------------------------------------------------------------------* * CLASS receiver IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS receiver IMPLEMENTATION. METHOD action. WRITE: / 'Console.WriteLine(Called Receiver.Action()'. ENDMETHOD. "action Version: 1.0 Side: 157

Project: Design Pattern ENDCLASS.

"receiver IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS command DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS command DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: constructor IMPORTING receiver TYPE REF TO receiver ,execute ABSTRACT. PROTECTED SECTION. DATA: receiver TYPE REF TO receiver. ENDCLASS. "command DEFINITION *----------------------------------------------------------------------* * CLASS command IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS command IMPLEMENTATION. METHOD constructor. me->receiver = receiver. ENDMETHOD. "constructor ENDCLASS. "command IMPLEMENTATION *----------------------------------------------------------------------* * CLASS concretecommand DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concretecommand DEFINITION INHERITING FROM command. PUBLIC SECTION. METHODS: execute REDEFINITION. ENDCLASS. "concretecommand DEFINITION *----------------------------------------------------------------------* * CLASS concretecommand IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS concretecommand IMPLEMENTATION. METHOD execute. me->receiver->action( ). ENDMETHOD. "execute ENDCLASS. "concretecommand IMPLEMENTATION *----------------------------------------------------------------------* * CLASS invoker DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS invoker DEFINITION. PUBLIC SECTION. METHODS: setcommand IMPORTING command TYPE REF TO command ,executecommand . PRIVATE SECTION.

Version: 1.0 Side: 158

Project: Design Pattern DATA: command TYPE REF TO command. ENDCLASS. "invoker DEFINITION *----------------------------------------------------------------------* * CLASS invoker IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS invoker IMPLEMENTATION. METHOD setcommand. me->command = command. ENDMETHOD. "setcommand METHOD executecommand. me->command->execute( ). ENDMETHOD. "executecommand ENDCLASS. "invoker IMPLEMENTATION *---------------------------------------------------------* CLASS lcl_application DEFINITION *---------------------------------------------------------CLASS lcl_application DEFINITION CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS: run. METHODS: constructor. PRIVATE SECTION. CLASS-DATA: so_application TYPE REF TO lcl_application. ENDCLASS. "lcl_application DEFINITION *---------------------------------------------------------* IMPLEMENTATION *---------------------------------------------------------CLASS lcl_application IMPLEMENTATION. *---------------------------------------------------------* LCL_APPLICATION->RUN(). *---------------------------------------------------------METHOD run. DATA: exc_ref TYPE REF TO cx_root ,exc_text TYPE string. IF lcl_application=>so_application IS INITIAL. TRY. CREATE OBJECT lcl_application=>so_application. CATCH cx_sy_create_object_error INTO exc_ref. exc_text = exc_ref->get_text( ). MESSAGE exc_text TYPE 'I'. ENDTRY. ENDIF. ENDMETHOD. "run *---------------------------------------------------------* LCL_APPLICATION->CONSTRUCTOR(). * Use the constructor for instantiating internal objects, * fields, tables and events. *---------------------------------------------------------METHOD constructor. DATA: receiver TYPE REF TO receiver ,command TYPE REF TO concretecommand

Version: 1.0 Side: 159

Project: Design Pattern ,invoker

TYPE REF TO invoker.

CREATE OBJECT receiver. CREATE OBJECT command EXPORTING receiver = receiver . CREATE OBJECT invoker. *

set and execute command invoker->setcommand( command ). invoker->executecommand( ). ENDMETHOD.

"constructor

ENDCLASS.

"lcl_application IMPLEMENTATION

START-OF-SELECTION. lcl_application=>run( ). Output: Program ZDP_COMMAND_STRUCTURAL Console.WriteLine(Called Receiver.Action()

2.3.2.6 Sample code In C# This real-world code demonstrates the Command pattern used in a simple calculator with unlimited number of undo's and redo's. Note that in C# the word 'operator' is a keyword. Prefixing it with '@' allows using it as an identifier. // Command pattern -- Real World example using System; using System.Collections; namespace DoFactory.GangOfFour.Command.RealWorld { // MainApp test application class MainApp { static void Main() { // Create user and let her compute User user = new User(); user.Compute('+', user.Compute('-', user.Compute('*', user.Compute('/', // Undo 4 commands user.Undo(4); // Redo 3 commands user.Redo(3);

Version: 1.0 Side: 160

100); 50); 10); 2);

Project: Design Pattern

// Wait for user Console.Read(); } } // "Command" abstract class Command { public abstract void Execute(); public abstract void UnExecute(); } // "ConcreteCommand" class CalculatorCommand : Command { char @operator; int operand; Calculator calculator; // Constructor public CalculatorCommand(Calculator calculator, char @operator, int operand) { this.calculator = calculator; this.@operator = @operator; this.operand = operand; } public char Operator { set{ @operator = value; } } public int Operand { set{ operand = value; } } public override void Execute() { calculator.Operation(@operator, operand); } public override void UnExecute() { calculator.Operation(Undo(@operator), operand); } // Private helper function private char Undo(char @operator) { char undo; switch(@operator) Version: 1.0 Side: 161

Project: Design Pattern { case '+': case '-': case '*': case '/': default :

undo undo undo undo undo

= = = = =

'-'; '+'; '/'; '*'; ' ';

break; break; break; break; break;

} return undo; } } // "Receiver" class Calculator { private int curr = 0; public void Operation(char @operator, int operand) { switch(@operator) { case '+': curr += operand; break; case '-': curr -= operand; break; case '*': curr *= operand; break; case '/': curr /= operand; break; } Console.WriteLine( "Current value = {0,3} (following {1} {2})", curr, @operator, operand); } } // "Invoker" class User { // Initializers private Calculator calculator = new Calculator(); private ArrayList commands = new ArrayList(); private int current = 0; public void Redo(int levels) { Console.WriteLine("\n---- Redo {0} levels ", levels); / / Perform redo operations for (int i = 0; i < levels; i++) { if (current < commands.Count - 1) { Command command = commands[current++] as Command; command.Execute(); } } }

Version: 1.0 Side: 162

Project: Design Pattern public void Undo(int levels) { Console.WriteLine("\n---- Undo {0} levels ", levels); // Perform undo operations for (int i = 0; i < levels; i++) { if (current > 0) { Command command = commands[--current] as Command; command.UnExecute(); } } } public void Compute(char @operator, int operand) { // Create command operation and execute it Command command = new CalculatorCommand( calculator, @operator, operand); command.Execute(); // Add command to undo list commands.Add(command); current++; } } }

Output Current Current Current Current

value value value value

= 100 (following + 100) = 50 (following - 50) = 500 (following * 10) = 250 (following / 2)

---- Undo 4 levels Current value = 500 Current value = 50 Current value = 100 Current value = 0

(following (following (following (following

* / + -

2) 10) 50) 100)

---- Redo 3 levels Current value = 100 (following + 100) Current value = 50 (following - 50) Current value = 500 (following * 10)

2.3.2.7 Sample code In C# This real-world code demonstrates the Command pattern used in a simple calculator with unlimited number of undo's and redo's. Note that in C# the word 'operator' is a keyword. Prefixing it with '@' allows using it as an identifier. *&---------------------------------------------------------------------* *& Report ZDP_COMMAND_REALWORLD *& *&---------------------------------------------------------------------* Version: 1.0 Side: 163

Project: Design Pattern *& *& *&---------------------------------------------------------------------* REPORT

zdp_command_realworld.

*----------------------------------------------------------------------* * CLASS command DEFINITION *----------------------------------------------------------------------* * An abstract class does not have implementations for abstract methods *----------------------------------------------------------------------* CLASS command DEFINITION ABSTRACT. PUBLIC SECTION. METHODS: execute ABSTRACT ,unexecute ABSTRACT . ENDCLASS. "command DEFINITION

*----------------------------------------------------------------------* * CLASS calculator DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS calculator DEFINITION. PUBLIC SECTION. METHODS: operation IMPORTING operator TYPE char1 operand TYPE i. PRIVATE SECTION. DATA: curr TYPE i VALUE 0. ENDCLASS. "calculator DEFINITION *----------------------------------------------------------------------* * CLASS calculator IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS calculator IMPLEMENTATION. METHOD operation. CASE operator. WHEN '+'. curr = curr + operand. WHEN '-'. curr = curr - operand. WHEN '*'. curr = curr * operand. WHEN '/'. curr = curr / operand. ENDCASE. WRITE: / 'Current Value = ', curr, '(following', (1) operator, (3) operand, ')'. ENDMETHOD. "operation ENDCLASS. "calculator IMPLEMENTATION *----------------------------------------------------------------------* * CLASS calculatorcommand DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------*

Version: 1.0 Side: 164

Project: Design Pattern CLASS calculatorcommand DEFINITION INHERITING FROM command. PUBLIC SECTION. DATA: calculator TYPE REF TO calculator ,_operand TYPE REF TO zcl_integer ,_operator TYPE REF TO zcl_char . METHODS: constructor IMPORTING calculator TYPE REF TO calculator operator TYPE char1 operand TYPE i ,operator IMPORTING operator TYPE char1 ,operand IMPORTING operand TYPE i ,execute REDEFINITION ,unexecute REDEFINITION . PRIVATE SECTION. METHODS: undo IMPORTING operator TYPE char1 RETURNING value(newoperator) TYPE char1. ENDCLASS. "calculatorcommand DEFINITION *----------------------------------------------------------------------* * CLASS calculatorcommand IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS calculatorcommand IMPLEMENTATION. METHOD constructor. super->constructor( ). me->calculator = calculator. CREATE OBJECT me->_operand. me->_operand->set( operand ). CREATE OBJECT me->_operator. me->_operator->set( operator ). ENDMETHOD. "constructor METHOD operator. me->_operator->set( operator ). ENDMETHOD. "operator METHOD operand. me->_operand->set( operand ). ENDMETHOD. "operand METHOD execute. DATA: l_operator TYPE char1 ,l_operand TYPE integer. l_operator = _operator->get( ). l_operand = _operand->get( ). me->calculator->operation( operator = l_operator operand = l_operand ). ENDMETHOD. "execute METHOD unexecute. DATA: l_operand TYPE integer ,l_operator TYPE char1 . l_operand = _operand->get( ).

Version: 1.0 Side: 165

Project: Design Pattern l_operator = _operator->get( ). l_operator = me->undo( l_operator ). me->calculator->operation( operator = l_operator operand = l_operand ). ENDMETHOD. "unexecute METHOD undo. CASE operator. WHEN '+'. newoperator = '-'. WHEN '-'. newoperator = '+'. WHEN '*'. newoperator = '/'. WHEN '/'. newoperator = '*'. WHEN OTHERS. newoperator = ' '. ENDCASE. ENDMETHOD. "undo ENDCLASS.

"calculatorcommand IMPLEMENTATION

*----------------------------------------------------------------------* * CLASS user DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS user DEFINITION. PUBLIC SECTION. METHODS: constructor ,redo IMPORTING levels TYPE integer ,undo IMPORTING levels TYPE integer ,compute IMPORTING operator TYPE char1 operand TYPE integer . PRIVATE SECTION. DATA: calculator TYPE REF TO calculator ,commands TYPE TABLE OF REF TO command ,current TYPE integer VALUE 0 ,command TYPE REF TO calculatorcommand . ENDCLASS.

"user DEFINITION

*----------------------------------------------------------------------* * CLASS user IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS user IMPLEMENTATION. METHOD constructor. CREATE OBJECT calculator. ENDMETHOD. "constructor METHOD redo. DATA: i TYPE integer VALUE 1 ,count TYPE i ,l_command TYPE REF TO command ,my_command TYPE REF TO calculatorcommand

Version: 1.0 Side: 166

Project: Design Pattern . DESCRIBE TABLE commands LINES count. SUBTRACT 1 FROM count. WRITE: /, / '----Redo levels ', levels. * perform redo operations WHILE i 0. READ TABLE commands INDEX current INTO l_command . SUBTRACT 1 FROM current. my_command ?= l_command. l_command->unexecute( ). ENDIF. ADD 1 TO i. ENDWHILE. ENDMETHOD. "undo

*

METHOD compute. // Create command operation and execute it CREATE OBJECT command EXPORTING calculator = calculator operator = operator operand = operand. me->command->execute( ). APPEND me->command TO commands. ADD 1 TO current. ENDMETHOD. "compute

ENDCLASS. "user IMPLEMENTATION *---------------------------------------------------------* CLASS lcl_application DEFINITION *---------------------------------------------------------CLASS lcl_application DEFINITION CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS: run. METHODS: constructor. PRIVATE SECTION. CLASS-DATA: so_application TYPE REF TO lcl_application. ENDCLASS. "lcl_application DEFINITION *---------------------------------------------------------* IMPLEMENTATION *----------------------------------------------------------

Version: 1.0 Side: 167

Project: Design Pattern CLASS lcl_application IMPLEMENTATION. *---------------------------------------------------------* LCL_APPLICATION->RUN(). *---------------------------------------------------------METHOD run. DATA: exc_ref TYPE REF TO cx_root ,exc_text TYPE string. IF lcl_application=>so_application IS INITIAL. TRY. CREATE OBJECT lcl_application=>so_application. CATCH cx_sy_create_object_error INTO exc_ref. exc_text = exc_ref->get_text( ). MESSAGE exc_text TYPE 'I'. ENDTRY. ENDIF. ENDMETHOD. "run METHOD constructor. DATA: user TYPE REF TO user. super->constructor( ). CREATE OBJECT user.

user->compute( operator user->compute( operator user->compute( operator user->compute( operator user->undo( 4 ). user->redo( 3 ). ENDMETHOD. ENDCLASS.

='+' ='-' ='*' ='/'

operand operand operand operand

= = = =

100 ). 50 ). 10 ). 2 ).

"constructor "lcl_application IMPLEMENTATION

START-OF-SELECTION. lcl_application=>run( ).

Report ZDP_COMMAND_REALWORLD Current Current Current Current

Value Value Value Value

= = = =

100 50 500 250

(following (following (following (following

+ 100 ) - 50 ) * 10 ) / 2 )

Undo levels Current Value = Current Value = Current Value = Current Value =

500 50 100 0

4 (following (following (following (following

* 2 / 10 + 50 - 100

Redo levels Current Value = Current Value = Current Value =

100 50 500

3 (following + 100 ) (following - 50 ) (following * 10 )

Version: 1.0 Side: 168

) ) ) )

Project: Design Pattern

2.3.3 Interpreter A way to include language elements in a program

2.3.3.1 Definition Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language

2.3.3.2 UML class diagram

2.3.3.3 Participants The classes and/or objects participating in this pattern are: • •



• •

AbstractExpression (Expression) o declares an interface for executing an operation TerminalExpression ( ThousandExpression, HundredExpression, TenExpression, OneExpression ) o implements an Interpret operation associated with terminal symbols in the grammar. o an instance is required for every terminal symbol in the sentence. NonterminalExpression ( not used ) o one such class is required for every rule R ::= R1R2...Rn in the grammar o maintains instance variables of type AbstractExpression for each of the symbols R1 through Rn. o implements an Interpret operation for nonterminal symbols in the grammar. Interpret typically calls itself recursively on the variables representing R1 through Rn. Context (Context) o contains information that is global to the interpreter Client (InterpreterApp) o builds (or is given) an abstract syntax tree representing a particular sentence in the language that the grammar defines. The abstract syntax tree is assembled from instances of the NonterminalExpression and TerminalExpression classes o invokes the Interpret operation

Version: 1.0 Side: 169

Project: Design Pattern

2.3.3.4 Sample code I C# This structural code demonstrates the Interpreter patterns, which using a defined grammer, provides the interpreter that processes parsed statements. // Interpreter pattern -- Structural example using System; using System.Collections; namespace DoFactory.GangOfFour.Interpreter.Structural { // MainApp test application class MainApp { static void Main() { Context context = new Context(); // Usually a tree ArrayList list = new ArrayList(); // Populate 'abstract syntax tree' list.Add(new TerminalExpression()); list.Add(new NonterminalExpression()); list.Add(new TerminalExpression()); list.Add(new TerminalExpression()); // Interpret foreach (AbstractExpression exp in list) { exp.Interpret(context); } // Wait for user Console.Read(); } } // "Context" class Context { } // "AbstractExpression" abstract class AbstractExpression { public abstract void Interpret(Context context); } // "TerminalExpression" class TerminalExpression : AbstractExpression

Version: 1.0 Side: 170

Project: Design Pattern { public override void Interpret(Context context) { Console.WriteLine("Called Terminal.Interpret()"); } } // "NonterminalExpression" class NonterminalExpression : AbstractExpression { public override void Interpret(Context context) { Console.WriteLine("Called Nonterminal.Interpret()"); } } }

Output Called Called Called Called

Terminal.Interpret() Nonterminal.Interpret() Terminal.Interpret() Terminal.Interpret()

This real-world code demonstrates the Interpreter pattern which is used to convert a Roman numeral to a decimal.

// Interpreter pattern -- Real World example using System; using System.Collections; namespace DoFactory.GangOfFour.Interpreter.RealWorld { // MainApp test application class MainApp { static void Main() { string roman = "MCMXXVIII"; Context context = new Context(roman); // Build the 'parse tree' ArrayList tree = new ArrayList(); tree.Add(new ThousandExpression()); tree.Add(new HundredExpression()); tree.Add(new TenExpression()); tree.Add(new OneExpression()); // Interpret foreach (Expression exp in tree) { Version: 1.0 Side: 171

Project: Design Pattern exp.Interpret(context); } Console.WriteLine("{0} = {1}", roman, context.Output); // Wait for user Console.Read(); } } // "Context" class Context { private string input; private int output; // Constructor public Context(string input) { this.input = input; } // Properties public string Input { get{ return input; } set{ input = value; } } public int Output { get{ return output; } set{ output = value; } } } // "AbstractExpression" abstract class Expression { public void Interpret(Context context) { if (context.Input.Length == 0) return; if (context.Input.StartsWith(Nine())) { context.Output += (9 * Multiplier()); context.Input = context.Input.Substring(2); } else if (context.Input.StartsWith(Four())) { context.Output += (4 * Multiplier()); context.Input = context.Input.Substring(2); Version: 1.0 Side: 172

Project: Design Pattern } else if (context.Input.StartsWith(Five())) { context.Output += (5 * Multiplier()); context.Input = context.Input.Substring(1); } while (context.Input.StartsWith(One())) { context.Output += (1 * Multiplier()); context.Input = context.Input.Substring(1); } } public public public public public

abstract abstract abstract abstract abstract

string One(); string Four(); string Five(); string Nine(); int Multiplier();

} // Thousand checks for the Roman Numeral M // "TerminalExpression" class ThousandExpression : Expression { public override string One() { return "M"; } public override string Four(){ return " "; } public override string Five(){ return " "; } public override string Nine(){ return " "; } public override int Multiplier() { return 1000; } } // Hundred checks C, CD, D or CM // "TerminalExpression" class HundredExpression : Expression { public override string One() { return "C"; } public override string Four(){ return "CD"; } public override string Five(){ return "D"; } public override string Nine(){ return "CM"; } public override int Multiplier() { return 100; } } // Ten checks for X, XL, L and XC // "TerminalExpression" class TenExpression : Expression { public override string One() { return "X"; } public override string Four(){ return "XL"; } public override string Five(){ return "L"; } public override string Nine(){ return "XC"; } public override int Multiplier() { return 10; } } Version: 1.0 Side: 173

Project: Design Pattern

// One checks for I, II, III, IV, V, VI, VI, VII, VIII, IX // "TerminalExpression" class OneExpression : Expression { public override string One() { return "I"; } public override string Four(){ return "IV"; } public override string Five(){ return "V"; } public override string Nine(){ return "IX"; } public override int Multiplier() { return 1; } } }

Output MCMXXVIII = 1928

2.3.4 Iterator Sequentially access the elements of a collection

2.3.4.1 Definition Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

2.3.4.2 UML class diagram

2.3.4.3 Participants The classes and/or objects participating in this pattern are: • •

Iterator (AbstractIterator) o defines an interface for accessing and traversing elements. ConcreteIterator (Iterator)

Version: 1.0 Side: 174

Project: Design Pattern

• •

o implements the Iterator interface. o keeps track of the current position in the traversal of the aggregate. Aggregate (AbstractCollection) o defines an interface for creating an Iterator object ConcreteAggregate (Collection) o implements the Iterator creation interface to return an instance of the proper ConcreteIterator

2.3.4.4 Sample code I C# This structural code demonstrates the Iterator pattern which provides for a way to traverse (iterate) over a collection of items without detailing the underlying structure of the collection. // Iterator pattern -- Structural example using System; using System.Collections; namespace DoFactory.GangOfFour.Iterator.Structural { // MainApp test application class MainApp { static void Main() { ConcreteAggregate a = new ConcreteAggregate(); a[0] = "Item A"; a[1] = "Item B"; a[2] = "Item C"; a[3] = "Item D"; // Create Iterator and provide aggregate ConcreteIterator i = new ConcreteIterator(a); Console.WriteLine("Iterating over collection:"); object item = i.First(); while (item != null) { Console.WriteLine(item); item = i.Next(); } // Wait for user Console.Read(); } } // "Aggregate" abstract class Aggregate Version: 1.0 Side: 175

Project: Design Pattern { public abstract Iterator CreateIterator(); } // "ConcreteAggregate" class ConcreteAggregate : Aggregate { private ArrayList items = new ArrayList(); public override Iterator CreateIterator() { return new ConcreteIterator(this); } // Property public int Count { get{ return items.Count; } } // Indexer public object this[int index] { get{ return items[index]; } set{ items.Insert(index, value); } } } // "Iterator" abstract { public public public public }

class Iterator abstract abstract abstract abstract

object First(); object Next(); bool IsDone(); object CurrentItem();

// "ConcreteIterator" class ConcreteIterator : Iterator { private ConcreteAggregate aggregate; private int current = 0; // Constructor public ConcreteIterator(ConcreteAggregate aggregate) { this.aggregate = aggregate; } public override object First() { return aggregate[0]; } Version: 1.0 Side: 176

Project: Design Pattern

public override object Next() { object ret = null; if (current < aggregate.Count - 1) { ret = aggregate[++current]; } return ret; } public override object CurrentItem() { return aggregate[current]; } public override bool IsDone() { return current >= aggregate.Count ? true : false ; } } }

Output Iterating over collection: Item A Item B Item C Item D

This real-world code demonstrates the Iterator pattern which is used to iterate over a collection of items and skip a specific number of items each iteration. // Iterator pattern -- Real World example using System; using System.Collections; namespace DoFactory.GangOfFour.Iterator.RealWorld { // MainApp test application class MainApp { static void Main() { // Build a collection Collection collection = new Collection(); collection[0] = new Item("Item 0"); collection[1] = new Item("Item 1"); collection[2] = new Item("Item 2"); collection[3] = new Item("Item 3"); collection[4] = new Item("Item 4"); Version: 1.0 Side: 177

Project: Design Pattern collection[5] collection[6] collection[7] collection[8]

= = = =

new new new new

Item("Item Item("Item Item("Item Item("Item

5"); 6"); 7"); 8");

// Create iterator Iterator iterator = new Iterator(collection); // Skip every other item iterator.Step = 2; Console.WriteLine("Iterating over collection:"); for(Item item = iterator.First(); !iterator.IsDone; item = iterator.Next()) { Console.WriteLine(item.Name); } // Wait for user Console.Read(); } } class Item { string name; // Constructor public Item(string name) { this.name = name; } // Property public string Name { get{ return name; } } } // "Aggregate" interface IAbstractCollection { Iterator CreateIterator(); } // "ConcreteAggregate" class Collection : IAbstractCollection { private ArrayList items = new ArrayList(); public Iterator CreateIterator() { Version: 1.0 Side: 178

Project: Design Pattern return new Iterator(this); } // Property public int Count { get{ return items.Count; } } // Indexer public object this[int index] { get{ return items[index]; } set{ items.Add(value); } } } // "Iterator" interface IAbstractIterator { Item First(); Item Next(); bool IsDone{ get; } Item CurrentItem{ get; } } // "ConcreteIterator" class Iterator : IAbstractIterator { private Collection collection; private int current = 0; private int step = 1; // Constructor public Iterator(Collection collection) { this.collection = collection; } public Item First() { current = 0; return collection[current] as Item; } public Item Next() { current += step; if (!IsDone) return collection[current] as Item; else return null; }

Version: 1.0 Side: 179

Project: Design Pattern // Properties public int Step { get{ return step; } set{ step = value; } } public Item CurrentItem { get { return collection[current] as Item; } } public bool IsDone { get { return current >= collection.Count ? true : false; } } } }

Output Iterating over collection: Item 0 Item 2 Item 4 Item 6 Item 8

2.3.5 Mediator Defines simplified communication between classes

2.3.5.1 Definition Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently

Version: 1.0 Side: 180

Project: Design Pattern

2.3.5.2 UML class diagram

2.3.5.3 Participants The classes and/or objects participating in this pattern are: • •



Mediator (IChatroom) o defines an interface for communicating with Colleague objects ConcreteMediator (Chatroom) o implements cooperative behavior by coordinating Colleague objects o knows and maintains its colleagues Colleague classes (Participant) o each Colleague class knows its Mediator object o each colleague communicates with its mediator whenever it would have otherwise communicated with another colleague

2.3.5.4 Sample code I C# This structural code demonstrates the Mediator pattern facilitating loosely coupled communication between different objects and object types. The mediator is a central hub through which all interaction must take place. // Mediator pattern -- Structural example using System; using System.Collections; namespace DoFactory.GangOfFour.Mediator.Structural { // Mainapp test application class MainApp { static void Main() { ConcreteMediator m = new ConcreteMediator();

Version: 1.0 Side: 181

Project: Design Pattern ConcreteColleague1 c1 = new ConcreteColleague1(m); ConcreteColleague2 c2 = new ConcreteColleague2(m); m.Colleague1 = c1; m.Colleague2 = c2; c1.Send("How are you?"); c2.Send("Fine, thanks"); // Wait for user Console.Read(); } } // "Mediator" abstract class Mediator { public abstract void Send(string message, Colleague colleague); } // "ConcreteMediator" class ConcreteMediator : Mediator { private ConcreteColleague1 colleague1; private ConcreteColleague2 colleague2; public ConcreteColleague1 Colleague1 { set{ colleague1 = value; } } public ConcreteColleague2 Colleague2 { set{ colleague2 = value; } } public override void Send(string message, Colleague colleague) { if (colleague == colleague1) { colleague2.Notify(message); } else { colleague1.Notify(message); } } } // "Colleague" abstract class Colleague Version: 1.0 Side: 182

Project: Design Pattern { protected Mediator mediator; // Constructor public Colleague(Mediator mediator) { this.mediator = mediator; } } // "ConcreteColleague1" class ConcreteColleague1 : Colleague { // Constructor public ConcreteColleague1(Mediator mediator) : base(mediator) { } public void Send(string message) { mediator.Send(message, this); } public void Notify(string message) { Console.WriteLine("Colleague1 gets message: " + message); } } // "ConcreteColleague2" class ConcreteColleague2 : Colleague { // Constructor public ConcreteColleague2(Mediator mediator) : base(mediator) { } public void Send(string message) { mediator.Send(message, this); } public void Notify(string message) { Console.WriteLine("Colleague2 gets message: " + message); } } }

Output

Version: 1.0 Side: 183

Project: Design Pattern

Colleague2 gets message: How are you? Colleague1 gets message: Fine, thanks

This real-world code demonstrates the Mediator pattern facilitating loosely coupled communication between different Participants registering with a Chatroom. The Chatroom is the central hub through which all communication takes place. At this point only one-toone communication is implemented in the Chatroom, but would be trivial to change to oneto-many. // Mediator pattern -- Real World example using System; using System.Collections; namespace DoFactory.GangOfFour.Mediator.RealWorld { // MainApp test application class MainApp { static void Main() { // Create chatroom Chatroom chatroom = new Chatroom(); // Create participants and register them Participant George = new Beatle("George"); Participant Paul = new Beatle("Paul"); Participant Ringo = new Beatle("Ringo"); Participant John = new Beatle("John") ; Participant Yoko = new NonBeatle("Yoko"); chatroom.Register(George); chatroom.Register(Paul); chatroom.Register(Ringo); chatroom.Register(John); chatroom.Register(Yoko); // Chatting participants Yoko.Send ("John", "Hi John!"); Paul.Send ("Ringo", "All you need is love"); Ringo.Send("George", "My sweet Lord"); Paul.Send ("John", "Can't buy me love"); John.Send ("Yoko", "My sweet love") ; // Wait for user Console.Read(); } } // "Mediator" abstract class AbstractChatroom Version: 1.0 Side: 184

Project: Design Pattern { public abstract void Register(Participant participant); public abstract void Send( string from, string to, string message); } // "ConcreteMediator" class Chatroom : AbstractChatroom { private Hashtable participants = new Hashtable(); public override void Register(Participant participant) { if (participants[participant.Name] == null) { participants[participant.Name] = participant; } participant.Chatroom = this; } public override void Send( string from, string to, string message) { Participant pto = (Participant)participants[to]; if (pto != null) { pto.Receive(from, message); } } } // "AbstractColleague" class Participant { private Chatroom chatroom; private string name; // Constructor public Participant(string name) { this.name = name; } // Properties public string Name { get{ return name; } } public Chatroom Chatroom { set{ chatroom = value; } get{ return chatroom; } Version: 1.0 Side: 185

Project: Design Pattern } public void Send(string to, string message) { chatroom.Send(name, to, message); } public virtual void Receive( string from, string message) { Console.WriteLine("{0} to {1}: '{2}'", from, Name, message); } } //" ConcreteColleague1" class Beatle : Participant { // Constructor public Beatle(string name) : base(name) { } public override void Receive(string from, string message) { Console.Write("To a Beatle: "); base.Receive(from, message); } } //" ConcreteColleague2" class NonBeatle : Participant { // Constructor public NonBeatle(string name) : base(name) { } public override void Receive(string from, string message) { Console.Write("To a non-Beatle: "); base.Receive(from, message); } } }

Output To To To To To

a a a a a

Beatle: Yoko to John: 'Hi John!' Beatle: Paul to Ringo: 'All you need is love' Beatle: Ringo to George: 'My sweet Lord' Beatle: Paul to John: 'Can't buy me love' non-Beatle: John to Yoko: 'My sweet love'

Version: 1.0 Side: 186

Project: Design Pattern

2.3.6 Memento Capture and restore an object's internal state

2.3.6.1 Definition Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.

2.3.6.2 UML class diagram

2.3.6.3 Participants The classes and/or objects participating in this pattern are: •





Memento (Memento) o stores internal state of the Originator object. The memento may store as much or as little of the originator's internal state as necessary at its originator's discretion. o protect against access by objects of other than the originator. Mementos have effectively two interfaces. Caretaker sees a narrow interface to the Memento -- it can only pass the memento to the other objects. Originator, in contrast, sees a wide interface, one that lets it access all the data necessary to restore itself to its previous state. Ideally, only the originator that produces the memento would be permitted to access the memento's internal state. Originator (SalesProspect) o creates a memento containing a snapshot of its current internal state. o uses the memento to restore its internal state Caretaker (Caretaker) o is responsible for the memento's safekeeping o never operates on or examines the contents of a memento.

2.3.6.4 Sample code I C# This structural code demonstrates the Memento pattern which temporary saves and restores another object's internal state. // Memento pattern -- Structural example using System; namespace DoFactory.GangOfFour.Memento.Structural { Version: 1.0 Side: 187

Project: Design Pattern

// MainApp test application class MainApp { static void Main() { Originator o = new Originator(); o.State = "On"; // Store internal state Caretaker c = new Caretaker(); c.Memento = o.CreateMemento(); // Continue changing originator o.State = "Off"; // Restore saved state o.SetMemento(c.Memento); // Wait for user Console.Read(); } } // "Originator" class Originator { private string state; // Property public string State { get{ return state; } set { state = value; Console.WriteLine("State = " + state); } } public Memento CreateMemento() { return (new Memento(state)); } public void SetMemento(Memento memento) { Console.WriteLine("Restoring state:"); State = memento.State; } } // "Memento"

Version: 1.0 Side: 188

Project: Design Pattern class Memento { private string state; // Constructor public Memento(string state) { this.state = state; } // Property public string State { get{ return state; } } } // "Caretaker" class Caretaker { private Memento memento; // Property public Memento Memento { set{ memento = value; } get{ return memento; } } } }

Output State = On State = Off Restoring state: State = On

This real-world code demonstrates the Memento pattern which temporarily saves and then restores the SalesProspect's internal state. // Memento pattern -- Real World example using System; namespace DoFactory.GangOfFour.Memento.RealWorld { // MainApp test application class MainApp { static void Main() { SalesProspect s = new SalesProspect(); Version: 1.0 Side: 189

Project: Design Pattern s.Name = "Noel van Halen"; s.Phone = "(412) 256-0990"; s.Budget = 25000.0; // Store internal state ProspectMemory m = new ProspectMemory(); m.Memento = s.SaveMemento(); // Continue changing originator s.Name = "Leo Welch"; s.Phone = "(310) 209-7111"; s.Budget = 1000000.0; // Restore saved state s.RestoreMemento(m.Memento); // Wait for user Console.Read(); } } // "Originator" class SalesProspect { private string name; private string phone; private double budget; // Properties public string Name { get{ return name; } set { name = value; Console.WriteLine("Name: " + name); } } public string Phone { get{ return phone; } set { phone = value; Console.WriteLine("Phone: " + phone); } } public double Budget { get{ return budget; } set { budget = value; Version: 1.0 Side: 190

Project: Design Pattern Console.WriteLine("Budget: " + budget); } } public Memento SaveMemento() { Console.WriteLine("\nSaving state --\n"); return new Memento(name, phone, budget); } public void RestoreMemento(Memento memento) { Console.WriteLine("\nRestoring state --\n"); this.Name = memento.Name; this.Phone = memento.Phone; this.Budget = memento.Budget; } } // "Memento" class Memento { private string name; private string phone; private double budget; // Constructor public Memento(string name, string phone, double budget) { this.name = name; this.phone = phone; this.budget = budget; } // Properties public string Name { get{ return name; } set{ name = value; } } public string Phone { get{ return phone; } set{ phone = value; } } public double Budget { get{ return budget; } set{ budget = value; } } } // "Caretaker" Version: 1.0 Side: 191

Project: Design Pattern

class ProspectMemory { private Memento memento; // Property public Memento Memento { set{ memento = value; } get{ return memento; } } } }

Output Name: Noel van Halen Phone: (412) 256-0990 Budget: 25000 Saving state -Name: Leo Welch Phone: (310) 209-7111 Budget: 1000000 Restoring state -Name: Noel van Halen Phone: (412) 256-0990 Budget: 25000

2.3.7 Observer A way of notifying change to a number of classes

2.3.7.1 Definition Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Version: 1.0 Side: 192

Project: Design Pattern

2.3.7.2 UML class diagram

2.3.7.3 Participants The classes and/or objects participating in this pattern are: •



• •

Subject (Stock) o knows its observers. Any number of Observer objects may observe a subject o provides an interface for attaching and detaching Observer objects. ConcreteSubject (IBM) o stores state of interest to ConcreteObserver o sends a notification to its observers when its state changes Observer (IInvestor) o defines an updating interface for objects that should be notified of changes in a subject. ConcreteObserver (Investor) o maintains a reference to a ConcreteSubject object o stores state that should stay consistent with the subject's o implements the Observer updating interface to keep its state consistent with the subject's

2.3.7.4 Sample code I C# This structural code demonstrates the Observer pattern in which registered objects are notified of and updated with a state change. // Observer pattern -- Structural example using System; using System.Collections; namespace DoFactory.GangOfFour.Observer.Structural { Version: 1.0 Side: 193

Project: Design Pattern

// MainApp test application class MainApp { static void Main() { // Configure Observer pattern ConcreteSubject s = new ConcreteSubject(); s.Attach(new ConcreteObserver(s,"X")); s.Attach(new ConcreteObserver(s,"Y")); s.Attach(new ConcreteObserver(s,"Z")); // Change subject and notify observers s.SubjectState = "ABC"; s.Notify(); // Wait for user Console.Read(); } } // "Subject" abstract class Subject { private ArrayList observers = new ArrayList(); public void Attach(Observer observer) { observers.Add(observer); } public void Detach(Observer observer) { observers.Remove(observer); } public void Notify() { foreach (Observer o in observers) { o.Update(); } } } // "ConcreteSubject" class ConcreteSubject : Subject { private string subjectState; // Property public string SubjectState Version: 1.0 Side: 194

Project: Design Pattern { get{ return subjectState; } set{ subjectState = value; } } } // "Observer" abstract class Observer { public abstract void Update(); } // "ConcreteObserver" class ConcreteObserver : Observer { private string name; private string observerState; private ConcreteSubject subject; // Constructor public ConcreteObserver( ConcreteSubject subject, string name) { this.subject = subject; this.name = name; } public override void Update() { observerState = subject.SubjectState; Console.WriteLine("Observer {0}'s new state is {1}", name, observerState); } // Property public ConcreteSubject Subject { get { return subject; } set { subject = value; } } } }

Output Observer X's new state is ABC Observer Y's new state is ABC Observer Z's new state is ABC

This real-world code demonstrates the Observer pattern in which registered investors are notified every time a stock changes value. // Observer pattern -- Real World example

Version: 1.0 Side: 195

Project: Design Pattern using System; using System.Collections; namespace DoFactory.GangOfFour.Observer.RealWorld { // MainApp test application class MainApp { static void Main() { // Create investors Investor s = new Investor("Sorros"); Investor b = new Investor("Berkshire"); // Create IBM stock and attach investors IBM ibm = new IBM("IBM", 120.00); ibm.Attach(s); ibm.Attach(b); // Change ibm.Price ibm.Price ibm.Price ibm.Price

price, which notifies investors = 120.10; = 121.00; = 120.50; = 120.75;

// Wait for user Console.Read(); } } // "Subject" abstract class Stock { protected string symbol; protected double price; private ArrayList investors = new ArrayList(); // Constructor public Stock(string symbol, double price) { this.symbol = symbol; this.price = price; } public void Attach(Investor investor) { investors.Add(investor); } public void Detach(Investor investor) { investors.Remove(investor); } Version: 1.0 Side: 196

Project: Design Pattern

public void Notify() { foreach (Investor investor in investors) { investor.Update(this); } Console.WriteLine(""); } // Properties public double Price { get{ return price; } set { price = value; Notify(); } } public string Symbol { get{ return symbol; } set{ symbol = value; } } } // "ConcreteSubject" class IBM : Stock { // Constructor public IBM(string symbol, double price) : base(symbol, price) { } } // "Observer" interface IInvestor { void Update(Stock stock); } // "ConcreteObserver" class Investor : IInvestor { private string name; private Stock stock; // Constructor public Investor(string name) { Version: 1.0 Side: 197

Project: Design Pattern this.name = name; } public void Update(Stock stock) { Console.WriteLine("Notified {0} of {1}'s " + "change to {2:C}", name, stock.Symbol, stock.Price); } // Property public Stock Stock { get{ return stock; } set{ stock = value; } } } }

Output Notified Sorros of IBM's change to $120.10 Notified Berkshire of IBM's change to $120.10 Notified Sorros of IBM's change to $121.00 Notified Berkshire of IBM's change to $121.00 Notified Sorros of IBM's change to $120.50 Notified Berkshire of IBM's change to $120.50 Notified Sorros of IBM's change to $120.75 Notified Berkshire of IBM's change to $120.75

2.3.8 State Alter an object's behavior when its state changes

2.3.8.1 Definition Allow an object to alter its behavior when its internal state changes. The object will appear to change its class

2.3.8.2 UML class diagram

Version: 1.0 Side: 198

Project: Design Pattern

2.3.8.3 Participants The classes and/or objects participating in this pattern are: •





Context (Account) o defines the interface of interest to clients o maintains an instance of a ConcreteState subclass that defines the current state. State (State) o defines an interface for encapsulating the behavior associated with a particular state of the Context. Concrete State (RedState, SilverState, GoldState) o each subclass implements a behavior associated with a state of Context

2.3.8.4 Sample code I C# This structural code demonstrates the State pattern which allows an object to behave differently depending on its internal state. The difference in behavior is delegated to objects that represent this state. // State pattern -- Structural example using System; namespace DoFactory.GangOfFour.State.Structural { // MainApp test application class MainApp { static void Main() { // Setup context in a state Context c = new Context(new ConcreteStateA()); // Issue requests, which toggles state c.Request(); c.Request(); c.Request(); c.Request(); // Wait for user Console.Read(); } } // "State" abstract class State { public abstract void Handle(Context context); Version: 1.0 Side: 199

Project: Design Pattern } // "ConcreteStateA" class ConcreteStateA : State { public override void Handle(Context context) { context.State = new ConcreteStateB(); } } // "ConcreteStateB" class ConcreteStateB : State { public override void Handle(Context context) { context.State = new ConcreteStateA(); } } // "Context" class Context { private State state; // Constructor public Context(State state) { this.State = state; } // Property public State State { get{ return state; } set { state = value; Console.WriteLine("State: " + state.GetType().Name); } } public void Request() { state.Handle(this); } } }

Output State: ConcreteStateA State: ConcreteStateB State: ConcreteStateA Version: 1.0 Side: 200

Project: Design Pattern State: ConcreteStateB State: ConcreteStateA

This real-world code demonstrates the State pattern which allows an Account to behave differently depending on its balance. The difference in behavior is delegated to State objects called RedState, SilverState and GoldState. These states represent overdrawn accounts, starter accounts, and accounts in good standing. // State pattern -- Real World example using System; namespace DoFactory.GangOfFour.State.RealWorld { // MainApp test application class MainApp { static void Main() { // Open a new account Account account = new Account("Jim Johnson"); // Apply financial transactions account.Deposit(500.0); account.Deposit(300.0); account.Deposit(550.0); account.PayInterest(); account.Withdraw(2000.00); account.Withdraw(1100.00); // Wait for user Console.Read(); } } // "State" abstract class State { protected Account account; protected double balance; protected double interest; protected double lowerLimit; protected double upperLimit; // Properties public Account Account { get{ return account; } set{ account = value; } }

Version: 1.0 Side: 201

Project: Design Pattern public double Balance { get{ return balance; } set{ balance = value; } } public abstract void Deposit(double amount); public abstract void Withdraw(double amount); public abstract void PayInterest(); } // "ConcreteState" // Account is overdrawn class RedState : State { double serviceFee; // Constructor public RedState(State state) { this.balance = state.Balance; this.account = state.Account; Initialize(); } private void Initialize() { // Should come from a datasource interest = 0.0; lowerLimit = -100.0; upperLimit = 0.0; serviceFee = 15.00; } public override void Deposit(double amount) { balance += amount; StateChangeCheck(); } public override void Withdraw(double amount) { amount = amount - serviceFee; Console.WriteLine("No funds available for withdrawal!"); } public override void PayInterest() { // No interest is paid } private void StateChangeCheck() { if (balance > upperLimit) Version: 1.0 Side: 202

Project: Design Pattern { account.State = new SilverState(this); } } } // "ConcreteState" // Silver is non-interest bearing state class SilverState : State { // Overloaded constructors public SilverState(State state) : this( state.Balance, state.Account) { } public SilverState(double balance, Account account) { this.balance = balance; this.account = account; Initialize(); } private void Initialize() { // Should come from a datasource interest = 0.0; lowerLimit = 0.0; upperLimit = 1000.0; } public override void Deposit(double amount) { balance += amount; StateChangeCheck(); } public override void Withdraw(double amount) { balance -= amount; StateChangeCheck(); } public override void PayInterest() { balance += interest * balance; StateChangeCheck(); } private void StateChangeCheck() { if (balance < lowerLimit) { Version: 1.0 Side: 203

Project: Design Pattern account.State = new RedState(this); } else if (balance > upperLimit) { account.State = new GoldState(this); } } } // "ConcreteState" // Interest bearing state class GoldState : State { // Overloaded constructors public GoldState(State state) : this(state.Balance,state.Account) { } public GoldState(double balance, Account account) { this.balance = balance; this.account = account; Initialize(); } private void Initialize() { // Should come from a database interest = 0.05; lowerLimit = 1000.0; upperLimit = 10000000.0; } public override void Deposit(double amount) { balance += amount; StateChangeCheck(); } public override void Withdraw(double amount) { balance -= amount; StateChangeCheck(); } public override void PayInterest() { balance += interest * balance; StateChangeCheck(); } private void StateChangeCheck() { Version: 1.0 Side: 204

Project: Design Pattern if (balance < 0.0) { account.State = new RedState(this); } else if (balance < lowerLimit) { account.State = new SilverState(this); } } } // "Context" class Account { private State state; private string owner; // Constructor public Account(string owner) { // New accounts are 'Silver' by default this.owner = owner; state = new SilverState(0.0, this); } // Properties public double Balance { get{ return state.Balance; } } public State State { get{ return state; } set{ state = value; } } public void Deposit(double amount) { state.Deposit(amount); Console.WriteLine("Deposited {0:C} --- ", amount); Console.WriteLine(" Balance = {0:C}", this.Balance); Console.WriteLine(" Status = {0}\n" , this.State.GetType().Name); Console.WriteLine(""); } public void Withdraw(double amount) { state.Withdraw(amount); Console.WriteLine("Withdrew {0:C} --- ", amount); Console.WriteLine(" Balance = {0:C}", this.Balance); Console.WriteLine(" Status = {0}\n" , this.State.GetType().Name); } Version: 1.0 Side: 205

Project: Design Pattern

public void PayInterest() { state.PayInterest(); Console.WriteLine("Interest Paid --- "); Console.WriteLine(" Balance = {0:C}", this.Balance); Console.WriteLine(" Status = {0}\n" , this.State.GetType().Name); } } }

Output Deposited $500.00 --Balance = $500.00 Status = SilverState

Deposited $300.00 --Balance = $800.00 Status = SilverState

Deposited $550.00 --Balance = $1,350.00 Status = GoldState

Interest Paid --Balance = $1,417.50 Status = GoldState Withdrew $2,000.00 --Balance = ($582.50) Status = RedState No funds available for withdrawal! Withdrew $1,100.00 --Balance = ($582.50) Status = RedState

2.3.9 Strategy Encapsulates an algorithm inside a class

2.3.9.1 Definition Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it

Version: 1.0 Side: 206

Project: Design Pattern

2.3.9.2 UML class diagram

2.3.9.3 Participants The classes and/or objects participating in this pattern are: •

• •

Strategy (SortStrategy) o declares an interface common to all supported algorithms. Context uses this interface to call the algorithm defined by a ConcreteStrategy ConcreteStrategy (QuickSort, ShellSort, MergeSort) o implements the algorithm using the Strategy interface Context (SortedList) o is configured with a ConcreteStrategy object o maintains a reference to a Strategy object o may define an interface that lets Strategy access its data.

2.3.9.4 Sample code In C# This structural code demonstrates the Strategy pattern which encapsulates functionality in the form of an object. This allows clients to dynamically change algorithmic strategies. // Strategy pattern -- Structural example using System; namespace DoFactory.GangOfFour.Strategy.Structural { // MainApp test application class MainApp { static void Main() { Context context; // Three contexts following different strategies context = new Context(new ConcreteStrategyA()); context.ContextInterface();

Version: 1.0 Side: 207

Project: Design Pattern context = new Context(new ConcreteStrategyB()); context.ContextInterface(); context = new Context(new ConcreteStrategyC()); context.ContextInterface(); // Wait for user Console.Read(); } } // "Strategy" abstract class Strategy { public abstract void AlgorithmInterface(); } // "ConcreteStrategyA" class ConcreteStrategyA : Strategy { public override void AlgorithmInterface() { Console.WriteLine( "Called ConcreteStrategyA.AlgorithmInterface()"); } } // "ConcreteStrategyB" class ConcreteStrategyB : Strategy { public override void AlgorithmInterface() { Console.WriteLine( "Called ConcreteStrategyB.AlgorithmInterface()"); } } // "ConcreteStrategyC" class ConcreteStrategyC : Strategy { public override void AlgorithmInterface() { Console.WriteLine( "Called ConcreteStrategyC.AlgorithmInterface()"); } } // "Context" class Context { Strategy strategy; Version: 1.0 Side: 208

Project: Design Pattern

// Constructor public Context(Strategy strategy) { this.strategy = strategy; } public void ContextInterface() { strategy.AlgorithmInterface(); } } }

Output Called ConcreteStrategyA.AlgorithmInterface() Called ConcreteStrategyB.AlgorithmInterface() Called ConcreteStrategyC.AlgorithmInterface()

This real-world code demonstrates the Strategy pattern which encapsulates sorting algorithms in the form of sorting objects. This allows clients to dynamically change sorting strategies including Quicksort, Shellsort, and Mergesort. // Strategy pattern -- Real World example using System; using System.Collections; namespace DoFactory.GangOfFour.Strategy.RealWorld { // MainApp test application class MainApp { static void Main() { // Two contexts following different strategies SortedList studentRecords = new SortedList(); studentRecords.Add("Samual"); studentRecords.Add("Jimmy"); studentRecords.Add("Sandra"); studentRecords.Add("Vivek"); studentRecords.Add("Anna"); studentRecords.SetSortStrategy(new QuickSort()); studentRecords.Sort(); studentRecords.SetSortStrategy(new ShellSort()); studentRecords.Sort(); studentRecords.SetSortStrategy(new MergeSort()); studentRecords.Sort();

Version: 1.0 Side: 209

Project: Design Pattern // Wait for user Console.Read(); } } // "Strategy" abstract class SortStrategy { public abstract void Sort(ArrayList list); } // "ConcreteStrategy" class QuickSort : SortStrategy { public override void Sort(ArrayList list) { list.Sort(); // Default is Quicksort Console.WriteLine("QuickSorted list "); } } // "ConcreteStrategy" class ShellSort : SortStrategy { public override void Sort(ArrayList list) { //list.ShellSort(); not-implemented Console.WriteLine("ShellSorted list "); } } // "ConcreteStrategy" class MergeSort : SortStrategy { public override void Sort(ArrayList list) { //list.MergeSort(); not-implemented Console.WriteLine("MergeSorted list "); } } // "Context" class SortedList { private ArrayList list = new ArrayList(); private SortStrategy sortstrategy; public void SetSortStrategy(SortStrategy sortstrategy) { this.sortstrategy = sortstrategy; } Version: 1.0 Side: 210

Project: Design Pattern

public void Add(string name) { list.Add(name); } public void Sort() { sortstrategy.Sort(list); // Display results foreach (string name in list) { Console.WriteLine(" " + name); } Console.WriteLine(); } } }

Output QuickSorted list Anna Jimmy Samual Sandra Vivek ShellSorted list Anna Jimmy Samual Sandra Vivek MergeSorted list Anna Jimmy Samual Sandra Vivek

2.3.10

Template Method

Defer the exact steps of an algorithm to a subclass

2.3.10.1

Definition

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure

Version: 1.0 Side: 211

Project: Design Pattern

2.3.10.2

UML class diagram

2.3.10.3

Participants

The classes and/or objects participating in this pattern are: •



AbstractClass (DataObject) o defines abstract primitive operations that concrete subclasses define to implement steps of an algorithm o implements a template method defining the skeleton of an algorithm. The template method calls primitive operations as well as operations defined in AbstractClass or those of other objects. ConcreteClass (CustomerDataObject) o implements the primitive operations ot carry out subclass-specific steps of the algorithm

2.3.10.4

Sample code In C#

This structural code demonstrates the Template method which provides a skeleton calling sequence of methods. One or more steps can be deferred to subclasses which implement these steps without changing the overall calling sequence. // Template pattern -- Structural example using System; namespace DoFactory.GangOfFour.Template.Structural { // MainApp test application class MainApp { static void Main() { AbstractClass c;

Version: 1.0 Side: 212

Project: Design Pattern c = new ConcreteClassA(); c.TemplateMethod(); c = new ConcreteClassB(); c.TemplateMethod(); // Wait for user Console.Read(); } } // "AbstractClass" abstract class AbstractClass { public abstract void PrimitiveOperation1(); public abstract void PrimitiveOperation2(); // The "Template method" public void TemplateMethod() { PrimitiveOperation1(); PrimitiveOperation2(); Console.WriteLine(""); } } // "ConcreteClass" class ConcreteClassA : AbstractClass { public override void PrimitiveOperation1() { Console.WriteLine("ConcreteClassA.PrimitiveOperation1()"); } public override void PrimitiveOperation2() { Console.WriteLine("ConcreteClassA.PrimitiveOperation2()"); } } class ConcreteClassB : AbstractClass { public override void PrimitiveOperation1() { Console.WriteLine("ConcreteClassB.PrimitiveOperation1()"); } public override void PrimitiveOperation2() { Console.WriteLine("ConcreteClassB.PrimitiveOperation2()"); } } }

Output Version: 1.0 Side: 213

Project: Design Pattern ConcreteClassA.PrimitiveOperation1() ConcreteClassA.PrimitiveOperation2()

This real-world code demonstrates a Template method named Run() which provides a skeleton calling sequence of methods. Implementation of these steps are deferred to the CustomerDataObject subclass which implements the Connect, Select, Process, and Disconnect methods. // Template pattern -- Real World example using System; using System.Data; using System.Data.OleDb; namespace DoFactory.GangOfFour.Template.RealWorld { // MainApp test application class MainApp { static void Main() { DataAccessObject dao; dao = new Categories(); dao.Run(); dao = new Products(); dao.Run(); // Wait for user Console.Read(); } } // "AbstractClass" abstract class DataAccessObject { protected string connectionString; protected DataSet dataSet; public virtual void Connect() { // Make sure mdb is on c:\ connectionString = "provider=Microsoft.JET.OLEDB.4.0; " + "data source=c:\\nwind.mdb"; } public abstract void Select(); public abstract void Process(); public virtual void Disconnect()

Version: 1.0 Side: 214

Project: Design Pattern { connectionString = ""; } // The "Template Method" public void Run() { Connect(); Select(); Process(); Disconnect(); } } // "ConcreteClass" class Categories : DataAccessObject { public override void Select() { string sql = "select CategoryName from Categories"; OleDbDataAdapter dataAdapter = new OleDbDataAdapter( sql, connectionString); dataSet = new DataSet(); dataAdapter.Fill(dataSet, "Categories"); } public override void Process() { Console.WriteLine("Categories ---- "); DataTable dataTable = dataSet.Tables["Categories"]; foreach (DataRow row in dataTable.Rows) { Console.WriteLine(row["CategoryName"]); } Console.WriteLine(); } } class Products : DataAccessObject { public override void Select() { string sql = "select ProductName from Products"; OleDbDataAdapter dataAdapter = new OleDbDataAdapter( sql, connectionString); dataSet = new DataSet(); dataAdapter.Fill(dataSet, "Products"); } public override void Process() { Version: 1.0 Side: 215

Project: Design Pattern Console.WriteLine("Products ---- "); DataTable dataTable = dataSet.Tables["Products"]; foreach (DataRow row in dataTable.Rows) { Console.WriteLine(row["ProductName"]); } Console.WriteLine(); } } }

Output Categories ---Beverages Condiments Confections Dairy Products Grains/Cereals Meat/Poultry Produce Seafood Products ---Chai Chang Aniseed Syrup Chef Anton's Cajun Seasoning Chef Anton's Gumbo Mix Grandma's Boysenberry Spread Uncle Bob's Organic Dried Pears Northwoods Cranberry Sauce Mishi Kobe Niku

2.3.11

Visitor

Defines a new operation to a class without change

2.3.11.1

Definition

Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

Version: 1.0 Side: 216

Project: Design Pattern

2.3.11.2

UML class diagram

2.3.11.3

Participants

The classes and/or objects participating in this pattern are: •



• •

Visitor (Visitor) o declares a Visit operation for each class of ConcreteElement in the object structure. The operation's name and signature identifies the class that sends the Visit request to the visitor. That lets the visitor determine the concrete class of the element being visited. Then the visitor can access the elements directly through its particular interface ConcreteVisitor (IncomeVisitor, VacationVisitor) o implements each operation declared by Visitor. Each operation implements a fragment of the algorithm defined for the corresponding class or object in the structure. ConcreteVisitor provides the context for the algorithm and stores its local state. This state often accumulates results during the traversal of the structure. Element (Element) o defines an Accept operation that takes a visitor as an argument. ConcreteElement (Employee)

Version: 1.0 Side: 217

Project: Design Pattern



o implements an Accept operation that takes a visitor as an argument ObjectStructure (Employees) o can enumerate its elements o may provide a high-level interface to allow the visitor to visit its elements o may either be a Composite (pattern) or a collection such as a list or a set

2.3.11.4

Sample code In C#

This structural code demonstrates the Visitor pattern in which an object traverses an object structure and performs the same operation on each node in this structure. Different visitor objects define different operations. // Visitor pattern -- Structural example using System; using System.Collections; namespace DoFactory.GangOfFour.Visitor.Structural { // MainApp test application class MainApp { static void Main() { // Setup structure ObjectStructure o = new ObjectStructure(); o.Attach(new ConcreteElementA()); o.Attach(new ConcreteElementB()); // Create visitor objects ConcreteVisitor1 v1 = new ConcreteVisitor1(); ConcreteVisitor2 v2 = new ConcreteVisitor2(); // Structure accepting visitors o.Accept(v1); o.Accept(v2); // Wait for user Console.Read(); } } // "Visitor" abstract class Visitor { public abstract void VisitConcreteElementA( ConcreteElementA concreteElementA); public abstract void VisitConcreteElementB( ConcreteElementB concreteElementB); }

Version: 1.0 Side: 218

Project: Design Pattern // "ConcreteVisitor1" class ConcreteVisitor1 : Visitor { public override void VisitConcreteElementA( ConcreteElementA concreteElementA) { Console.WriteLine("{0} visited by {1}", concreteElementA.GetType().Name, this.GetType().Name); } public override void VisitConcreteElementB( ConcreteElementB concreteElementB) { Console.WriteLine("{0} visited by {1}", concreteElementB.GetType().Name, this.GetType().Name); } } // "ConcreteVisitor2" class ConcreteVisitor2 : Visitor { public override void VisitConcreteElementA( ConcreteElementA concreteElementA) { Console.WriteLine("{0} visited by {1}", concreteElementA.GetType().Name, this.GetType().Name); } public override void VisitConcreteElementB( ConcreteElementB concreteElementB) { Console.WriteLine("{0} visited by {1}", concreteElementB.GetType().Name, this.GetType().Name); } } // "Element" abstract class Element { public abstract void Accept(Visitor visitor); } // "ConcreteElementA" class ConcreteElementA : Element { public override void Accept(Visitor visitor) { visitor.VisitConcreteElementA(this); } public void OperationA() { Version: 1.0 Side: 219

Project: Design Pattern } } // "ConcreteElementB" class ConcreteElementB : Element { public override void Accept(Visitor visitor) { visitor.VisitConcreteElementB(this); } public void OperationB() { } } // "ObjectStructure" class ObjectStructure { private ArrayList elements = new ArrayList(); public void Attach(Element element) { elements.Add(element); } public void Detach(Element element) { elements.Remove(element); } public void Accept(Visitor visitor) { foreach (Element e in elements) { e.Accept(visitor); } } } }

Output ConcreteElementA ConcreteElementB ConcreteElementA ConcreteElementB

visited visited visited visited

by by by by

ConcreteVisitor1 ConcreteVisitor1 ConcreteVisitor2 ConcreteVisitor2

This real-world code demonstrates the Visitor pattern in which two objects traverse a list of Employees and performs the same operation on each Employee. The two visitor objects define different operations -- one adjusts vacation days and the other income. // Visitor pattern -- Real World example Version: 1.0 Side: 220

Project: Design Pattern

using System; using System.Collections; namespace DoFactory.GangOfFour.Visitor.RealWorld { // MainApp startup application class MainApp { static void Main() { // Setup employee collection Employees e = new Employees(); e.Attach(new Clerk()); e.Attach(new Director()); e.Attach(new President()); // Employees are 'visited' e.Accept(new IncomeVisitor()); e.Accept(new VacationVisitor()); // Wait for user Console.Read(); } } // "Visitor" interface IVisitor { void Visit(Element element); } // "ConcreteVisitor1" class IncomeVisitor : IVisitor { public void Visit(Element element) { Employee employee = element as Employee; // Provide 10% pay raise employee.Income *= 1.10; Console.WriteLine("{0} {1}'s new income: {2:C}", employee.GetType().Name, employee.Name, employee.Income); } } // "ConcreteVisitor2" class VacationVisitor : IVisitor { public void Visit(Element element) Version: 1.0 Side: 221

Project: Design Pattern { Employee employee = element as Employee; // Provide 3 extra vacation days Console.WriteLine("{0} {1}'s new vacation days: {2}", employee.GetType().Name, employee.Name, employee.VacationDays); } } class Clerk : Employee { // Constructor public Clerk() : base("Hank", 25000.0, 14) { } } class Director : Employee { // Constructor public Director() : base("Elly", 35000.0, 16) { } } class President : Employee { // Constructor public President() : base("Dick", 45000.0, 21) { } } // "Element" abstract class Element { public abstract void Accept(IVisitor visitor); } // "ConcreteElement" class Employee : Element { string name; double income; int vacationDays; // Constructor public Employee(string name, double income, int vacationDays) { this.name = name; this.income = income; this.vacationDays = vacationDays; Version: 1.0 Side: 222

Project: Design Pattern } // Properties public string Name { get{ return name; } set{ name = value; } } public double Income { get{ return income; } set{ income = value; } } public int VacationDays { get{ return vacationDays; } set{ vacationDays = value; } } public override void Accept(IVisitor visitor) { visitor.Visit(this); } } // "ObjectStructure" class Employees { private ArrayList employees = new ArrayList(); public void Attach(Employee employee) { employees.Add(employee); } public void Detach(Employee employee) { employees.Remove(employee); } public void Accept(IVisitor visitor) { foreach (Employee e in employees) { e.Accept(visitor); } Console.WriteLine(); } } }

Output Version: 1.0 Side: 223

Project: Design Pattern Clerk Hank's new income: $27,500.00 Director Elly's new income: $38,500.00 President Dick's new income: $49,500.00 Clerk Hank's new vacation days: 14 Director Elly's new vacation days: 16 President Dick's new vacation days: 21

Version: 1.0 Side: 224

View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF