224
Design Patterns Implementation Of objects using design patterns in Abap Object Version: 1 Date: 2. Januar 2008

80142978 Design Patterns Abap Objects

Embed Size (px)

Citation preview

Page 1: 80142978 Design Patterns Abap Objects

Design Patterns

Implementation Of objects using design patterns in Abap Object

Version: 1 Date: 2. Januar 2008

Page 2: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: ii

Version management Date What has changed Sections Whom Version 01.12.2007 Creation of the document All BGS 1.0 Reference documents Document Version Location The Gang Of Four Participants Name Company Roll in the project Benny G. Sørensen BGS

Consulting ApS

Page 3: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 3

Contents:

1 INTRODUCTION 6 2 DESIGN PATTERNS 6

2.1 CREATIONAL PATTERNS 7 2.1.1 Abstract Factory 7

2.1.1.1 Definition 7 2.1.1.2 Commen Use 8 2.1.1.3 UML class diagram 10 2.1.1.4 Participants 10 2.1.1.5 Sample code in C# 10 2.1.1.6 Sample code in ABAP 13 2.1.1.7 Sample code in C# 16 2.1.1.8 Sample code in ABAP 18

2.1.2 Builder 21 2.1.2.1 Definition 21 2.1.2.2 Useful tips 21 2.1.2.3 UML class diagram 22 2.1.2.4 Participants 22 2.1.2.5 Sample code In C# 22 2.1.2.6 Sample code In ABAP 25 2.1.2.7 Sample code In C# 27 2.1.2.8 Sample code In ABAP 31

2.1.3 Factory Method 34 2.1.3.1 Definition 34 2.1.3.2 UML class diagram 35 2.1.3.3 Participants 35 2.1.3.4 Sample code In C# 35 2.1.3.5 Sample code in ABAP 40 2.1.3.6 Sample code in ABAP 42 2.1.3.7 Sample code in ABAP 44

2.1.4 Prototype 47 2.1.4.1 Definition 47 2.1.4.2 Used for 47 2.1.4.3 UML class diagram 48 2.1.4.4 Participants 48 2.1.4.5 Sample code In C# 48 2.1.4.6 Sample code In ABAP 50 2.1.4.7 Sample code In C# 52 2.1.4.8 Sample code In ABAP 54

2.1.5 Singleton 57 2.1.5.1 Definition 57 2.1.5.2 Common Use 57 2.1.5.3 Implementation 58 2.1.5.4 UML class diagram 59 2.1.5.5 Participants 59 2.1.5.6 Sample code In C# 59 2.1.5.7 Sample code In ABAP 60 2.1.5.8 Sample code In C# 62 2.1.5.9 Sample code In ABAP 64 2.1.5.10 Sample code In ABAP for Application 66

2.2 STRUCTURAL PATTERNS 67 2.2.1 Adapter 67

2.2.1.1 Definition 67 2.2.1.2 Common Use 68 2.2.1.3 UML class diagram 69 2.2.1.4 Participants 69

Page 4: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 4

2.2.1.5 Sample code In C# 69 2.2.1.6 Sample code In ABAP 70 2.2.1.7 Sample code In C# 72 2.2.1.8 Sample code In ABAP 75 2.2.1.9 Sample code In ABAP using interfaces 79

2.2.2 Bridge 83 2.2.2.1 Definition 83 2.2.2.2 Common Use 83 2.2.2.3 UML class diagram 84 2.2.2.4 Participants 84 2.2.2.5 Sample code In C# 84

2.2.3 Composite 84 2.2.3.1 Definition 84 2.2.3.2 UML class diagram 85 2.2.3.3 Participants 85 2.2.3.4 Sample code In C# 85 2.2.3.5 Sample code In ABAP 88 2.2.3.6 Sample code In C# 91 2.2.3.7 Sample code In ABAP 93

2.2.4 Decorator 96 2.2.4.1 Definition 96 2.2.4.2 UML class diagram 97 2.2.4.3 Participants 97 2.2.4.4 Sample code In C# 97 2.2.4.5 Sample code In ABAP 99 2.2.4.6 Sample code In C# 102 2.2.4.7 Sample code In ABAP 105

2.2.5 Facade 110 2.2.5.1 Definition 110 2.2.5.2 UML class diagram 110 2.2.5.3 Participants 110 2.2.5.4 Sample code In C# 111 2.2.5.5 Sample code In ABAP 113 2.2.5.6 Sample code In C# 116 2.2.5.7 Sample code In ABAP 118

2.2.6 Flyweight (fluevægt) 122 2.2.6.1 Definition 122 2.2.6.2 UML class diagram 122 2.2.6.3 Participants 122 2.2.6.4 Sample code In C# 123 2.2.6.5 Sample code In ABAP 124 2.2.6.6 Sample code In C# 127

2.2.7 Proxy 130 2.2.7.1 Definition 130 2.2.7.2 UML class diagram 131 2.2.7.3 Participants 131 2.2.7.4 Sample code In C# 131 2.2.7.5 Sample code In ABAP 133 2.2.7.6 Sample code In C# 135 2.2.7.7 Sample code In ABAP using interface 136

2.3 BEHAVIORAL PATTERNS 139 2.3.1 Chain of Resp. 139

2.3.1.1 Definition 139 2.3.1.2 UML class diagram 140 2.3.1.3 Participants 140 2.3.1.4 Sample code In C# 140 2.3.1.5 Sample code In ABAP 142 2.3.1.6 Sample code In C# 146

Page 5: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 5

2.3.1.7 Sample code In ABAP 149 2.3.2 Command 154

2.3.2.1 Definition 154 2.3.2.2 UML class diagram 155 2.3.2.3 Participants 155 2.3.2.4 Sample code In C# 155 2.3.2.5 Sample code in ABAP 157 2.3.2.6 Sample code In C# 160 2.3.2.7 Sample code In C# 163

2.3.3 Interpreter 169 2.3.3.1 Definition 169 2.3.3.2 UML class diagram 169 2.3.3.3 Participants 169 2.3.3.4 Sample code I C# 170

2.3.4 Iterator 174 2.3.4.1 Definition 174 2.3.4.2 UML class diagram 174 2.3.4.3 Participants 174 2.3.4.4 Sample code I C# 175

2.3.5 Mediator 180 2.3.5.1 Definition 180 2.3.5.2 UML class diagram 181 2.3.5.3 Participants 181 2.3.5.4 Sample code I C# 181

2.3.6 Memento 187 2.3.6.1 Definition 187 2.3.6.2 UML class diagram 187 2.3.6.3 Participants 187 2.3.6.4 Sample code I C# 187

2.3.7 Observer 192 2.3.7.1 Definition 192 2.3.7.2 UML class diagram 193 2.3.7.3 Participants 193 2.3.7.4 Sample code I C# 193

2.3.8 State 198 2.3.8.1 Definition 198 2.3.8.2 UML class diagram 198 2.3.8.3 Participants 199 2.3.8.4 Sample code I C# 199

2.3.9 Strategy 206 2.3.9.1 Definition 206 2.3.9.2 UML class diagram 207 2.3.9.3 Participants 207 2.3.9.4 Sample code In C# 207

2.3.10 Template Method 211 2.3.10.1 Definition 211 2.3.10.2 UML class diagram 212 2.3.10.3 Participants 212 2.3.10.4 Sample code In C# 212

2.3.11 Visitor 216 2.3.11.1 Definition 216 2.3.11.2 UML class diagram 217 2.3.11.3 Participants 217 2.3.11.4 Sample code In C# 218

Page 6: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 6

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

Page 7: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 7

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.

Page 8: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 8

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:

Page 9: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 9

• 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

Page 10: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 10

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

Page 11: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 11

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()

Page 12: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 12

{

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

{

Page 13: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 13

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.

Page 14: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 14

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.

Page 15: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 15

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 concretefactory1 ,factory2 TYPE REF TO concretefactory2 ,c1 TYPE REF TO client ,c2 TYPE REF TO 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. "main ENDCLASS. "mainapp IMPLEMENTATION START-OF-SELECTION. mainapp=>main( ).

Page 16: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 16

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()

{

Page 17: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 17

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

Page 18: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 18

{

}

// "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.

Page 19: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 19

&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 .

Page 20: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 20

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. "mainapp DEFINITION

Page 21: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 21

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. "main ENDCLASS. "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

Page 22: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 22

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

Page 23: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 23

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 class Builder

{

public abstract void BuildPartA();

public abstract void BuildPartB();

public abstract Product GetResult();

}

// "ConcreteBuilder1"

class ConcreteBuilder1 : Builder

Page 24: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 24

{

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)

Page 25: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 25

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

Page 26: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 26

. 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.

Page 27: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 27

ENDCLASS. "mainapp DEFINITION CLASS mainapp IMPLEMENTATION. METHOD main. DATA: director TYPE REF TO director ,b1 TYPE REF TO concretebuilder1 ,b2 TYPE REF TO concretebuilder2 ,p1 TYPE REF TO product ,p2 TYPE REF TO product . FIELD-SYMBOLS <fs> TYPE ANY. 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. "main ENDCLASS. "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();

Page 28: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 28

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 abstract void BuildFrame();

public abstract void BuildEngine();

public abstract void BuildWheels();

public abstract void BuildDoors();

}

// "ConcreteBuilder1"

class MotorCycleBuilder : VehicleBuilder

{

public override void BuildFrame()

Page 29: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 29

{

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";

}

Page 30: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 30

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

Page 31: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 31

--------------------------- 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.

Page 32: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 32

ENDMETHOD. "show ENDCLASS. "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. "vehicle METHOD show. vehicle->show( ). ENDMETHOD. "show ENDCLASS. "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

Page 33: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 33

,builddoors REDEFINITION . ENDCLASS. "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( ).

Page 34: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 34

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. "main ENDCLASS. "mainapp IMPLEMENTATION START-OF-SELECTION. mainapp=>main( ). Vehicle Type: Scooter frame Scooter Frame engine 50 cc wheels 2 doors 0 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.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.

Page 35: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 35

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

Page 36: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 36

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();

}

Page 37: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 37

}

// "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();

}

}

Page 38: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 38

// "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"

Page 39: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 39

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

Page 40: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 40

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 <instans object> <returning name> ?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 creator DEFINITION DEFERRED. CLASS concretecreatora DEFINITION DEFERRED. CLASS concretecreatorb DEFINITION DEFERRED. 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 product DEFINITION ABSTRACT. ENDCLASS. "product DEFINITION CLASS concreteproducta DEFINITION INHERITING FROM product. ENDCLASS. "concreteproducta DEFINITION CLASS concreteproductb DEFINITION INHERITING FROM product. ENDCLASS. "concreteproductB DEFINITION

Page 41: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 41

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 <fs> 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 <fs>. ?get_class_name <fs> class_name. CASE class_name. WHEN 'CONCRETECREATORA'. WRITE: / 'ConcreteCreatorA Creates Product A'. WHEN 'CONCRETECREATORB'. WRITE: / 'ConcreteCreatorB Creates Product B'. ENDCASE. creator = <fs>. product = creator->factorymethod( ). ?get_class_name product class_name. WRITE: / 'Product =',class_name. ENDLOOP.

Page 42: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 42

ENDMETHOD. "main ENDCLASS. "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.

Page 43: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 43

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 REF TO concretecreatora ,concretecreatorb TYPE REF TO concretecreatorb ,product TYPE REF TO product ,product_name(30) type c ,class_name TYPE abap_abstypename . FIELD-SYMBOLS <fs> TYPE REF 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 <fs>. * Call macro to find out which Creator and Product are active ?get_class_name <fs> class_name.

Page 44: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 44

CASE class_name. WHEN 'CONCRETECREATORA'. WRITE: / 'ConcreteCreatorA Creates Product A'. WHEN 'CONCRETECREATORB'. WRITE: / 'ConcreteCreatorB Creates Product B'. ENDCASE. product = <fs>->factorymethod( ) . ?get_class_name product class_name. product_name = product->get_name( ). WRITE: / 'Class= ', class_name,'Product =',product_name. ENDLOOP. ENDMETHOD. "main ENDCLASS. "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.

Page 45: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 45

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. "pages ENDCLASS. "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. "createpages ENDCLASS. "resume IMPLEMENTATION

Page 46: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 46

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. "createpages ENDCLASS. "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: <fs_document> TYPE REF TO document ,<fs_page> 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 <fs_document>. * Call macro to find out which Creator and Product are active ?get_class_name <fs_document> class_name. CASE class_name. WHEN 'RESUME'. WRITE: / 'Resume contains following pages:', / sy-uline. CALL METHOD <fs_document>->pages( IMPORTING pages = pages_coll ). * Loop at all pages in document Resume

Page 47: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 47

LOOP AT pages_coll ASSIGNING <fs_page>. ?get_class_name <fs_page> class_name. WRITE: / class_name. ENDLOOP. WHEN 'REPORT'. WRITE: / 'Report contains following pages:', / sy-uline. CALL METHOD <fs_document>->pages( IMPORTING pages = pages_coll ). * Loop at all pages in document Resume LOOP AT pages_coll ASSIGNING <fs_page>. ?get_class_name <fs_page> class_name. WRITE: / class_name. ENDLOOP. ENDCASE. ENDLOOP. ENDMETHOD. "main ENDCLASS. "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)

Page 48: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 48

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);

Page 49: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 49

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)

{

}

Page 50: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 50

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.

Page 51: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 51

ENDMETHOD. "get_id ENDCLASS. "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 *----------------------------------------------------------------------*

Page 52: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 52

* *----------------------------------------------------------------------* 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 <fs> 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. "endmethod ENDCLASS. "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()

Page 53: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 53

{

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 : ColorPrototype

{

private int red;

private int green;

private int 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()

{

Page 54: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 54

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 *& *&---------------------------------------------------------------------* *&

Page 55: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 55

*& *&---------------------------------------------------------------------* 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.

Page 56: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 56

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 <fs> 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 ).

Page 57: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 57

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 is a colorprototype !color ?= !color->clone( ). "!color is a color name = 'peace'. !color ?= colormanager->get( name ). "!color is a colorprototype !color ?= !color->clone( ). "!color is a color name = 'flame'. !color ?= colormanager->get( name ). "!color is a colorprototype !color ?= !color->clone( ). "!color is a color ENDMETHOD. "endmethod ENDCLASS. "mainapp IMPLEMENTATION START-OF-SELECTION. mainapp=>main( ). Output: Program ZPROTOTYPE_STRUCTURAL Cloning color RGB: {0,3},{1,3},{2,3} 255 0 0 Cloning color RGB: {0,3},{1,3},{2,3} 128 211 128 Cloning color RGB: {0,3},{1,3},{2,3} 211 34 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.

Page 58: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 58

• 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.

Page 59: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 59

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()

Page 60: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 60

{

// 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 *& *&---------------------------------------------------------------------* *& *&

Page 61: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 61

*&---------------------------------------------------------------------* 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.

Page 62: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 62

ENDMETHOD. "endmethod ENDCLASS. "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.GetLoadBalancer();

LoadBalancer b2 = LoadBalancer.GetLoadBalancer();

LoadBalancer b3 = LoadBalancer.GetLoadBalancer();

LoadBalancer b4 = 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();

}

}

Page 63: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 63

// "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();

}

}

}

}

Page 64: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 64

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 *----------------------------------------------------------------------*

Page 65: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 65

* 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. "server ENDCLASS. "singleton IMPLEMENTATION *----------------------------------------------------------------------* * CLASS mainapp DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS mainapp DEFINITION. PUBLIC SECTION. CLASS-METHODS: main. ENDCLASS. "mainapp DEFINITION *----------------------------------------------------------------------* * CLASS mainapp IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------*

Page 66: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 66

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 use create object b1 = loadbalancer=>getloadbalancer( ). b2 = loadbalancer=>getloadbalancer( ). b3 = loadbalancer=>getloadbalancer( ). b4 = loadbalancer=>getloadbalancer( ). 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. "endmethod ENDCLASS. "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

Page 67: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 67

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.

Page 68: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 68

ObjectAdapter

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

ClassAdapter

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.

Page 69: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 69

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();

Page 70: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 70

// 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

Page 71: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 71

*& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* 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 *----------------------------------------------------------------------*

Page 72: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 72

* 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. "endmethod ENDCLASS. "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

Page 73: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 73

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

{

Page 74: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 74

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(" Formula: {0}", molecularFormula);

Console.WriteLine(" Weight : {0}", molecularWeight);

Console.WriteLine(" Melting Pt: {0}", meltingPoint);

Console.WriteLine(" 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 = 0.0F; break;

case "benzene" : temperature = 5.5F; break;

case "alcohol" : temperature = -114.1F; break;

}

}

// Boiling Point

else

{

switch (compound.ToLower())

{

case "water" : temperature = 100.0F; break;

case "benzene" : temperature = 80.1F; break;

case "alcohol" : temperature = 78.3F; break;

}

}

return temperature;

}

Page 75: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 75

public string GetMolecularStructure(string compound)

{

string structure = "";

switch (compound.ToLower())

{

case "water" : structure = "H20"; break;

case "benzene" : structure = "C6H6"; break;

case "alcohol" : structure = "C2H6O2"; break;

}

return 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 *&

Page 76: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 76

*&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* 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

Page 77: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 77

*----------------------------------------------------------------------* * 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. "getmolecularweight ENDCLASS. "adaptee IMPLEMENTATION *----------------------------------------------------------------------* * CLASS Richcompound DEFINITION *----------------------------------------------------------------------*

Page 78: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 78

* *----------------------------------------------------------------------* 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. "request ENDCLASS. "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 .

Page 79: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 79

* 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. "endmethod ENDCLASS. "mainapp IMPLEMENTATION START-OF-SELECTION. mainapp=>main( ). OUTPUT: -------- Compound: Unknown Compound: Water Formula: H2O Weight: 18,0150 Melting Pt: 0,00 Boiling Pt: 100,00 Compound: Benzene Formula: C6H6 Weight: 78,1134 Melting Pt: 5,50 Boiling Pt: 80,10 Compound: Alcohol Formula: C2H6O2 Weight: 46,0688 Melting Pt: -114,10 Boiling Pt: 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. *&---------------------------------------------------------------------*

Page 80: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 80

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

Page 81: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 81

*----------------------------------------------------------------------* * 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.

Page 82: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 82

DATA: io_name TYPE string. 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: 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 på de enkelte figurer CREATE OBJECT o_cirkel EXPORTING r = 24. CREATE OBJECT o_trekant EXPORTING h = 2 g = 4. CREATE OBJECT o_firkant EXPORTING l = 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. "constructor ENDCLASS. "lcl_application IMPLEMENTATION START-OF-SELECTION.

Page 83: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 83

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

Page 84: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 84

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.

Page 85: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 85

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.

Page 86: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 86

// 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);

}

Page 87: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 87

// "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);

}

Page 88: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 88

}

}

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.

Page 89: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 89

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 <fs> TYPE REF TO component. data: index type sy-tabix. LOOP AT children ASSIGNING <fs>. index = sy-tabix. IF <fs> = component. EXIT. ENDIF. ENDLOOP. IF sy-subrc = 0. DELETE children INDEX index. ENDIF. ENDMETHOD. "remove METHOD display. FIELD-SYMBOLS <fs> TYPE REF TO component. DATA mydepth TYPE i. write: /. do depth times. write '-'. enddo. WRITE: me->name. mydepth = depth + 1. LOOP AT children ASSIGNING <fs>. <fs>->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.

Page 90: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 90

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'). myroot->add( myleaf ). myleaf = leaf=>new('Leaf B'). 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'). myroot->add( myleaf ).

Page 91: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 91

myleaf = leaf=>new('Leaf D'). myroot->add( myleaf ). myroot->remove( myleaf ). myroot->display( 1 ). ENDMETHOD. "endmethod ENDCLASS. "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

Page 92: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 92

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);

Page 93: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 93

} 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.

Page 94: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 94

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 <fs> TYPE REF TO drawingelement. DATA: index TYPE sy-tabix. LOOP AT elements ASSIGNING <fs>. index = sy-tabix. IF <fs> = drawingelement. EXIT. ENDIF. ENDLOOP. IF sy-subrc = 0. DELETE elements INDEX index. ENDIF. ENDMETHOD. "remove METHOD display. FIELD-SYMBOLS <fs> TYPE REF TO drawingelement. DATA myindent TYPE i. WRITE: /. DO indent TIMES. WRITE '-'. ENDDO.

Page 95: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 95

WRITE: '+' , me->name. myindent = indent + 2. LOOP AT elements ASSIGNING <fs>. <fs>->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

Page 96: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 96

*----------------------------------------------------------------------* * 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'). myroot->add( myprimitiveelement ). myroot->remove( myprimitiveelement ). myroot->display( 1 ). ENDMETHOD. "endmethod ENDCLASS. "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.

Page 97: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 97

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

{

Page 98: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 98

// 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();

}

Page 99: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 99

}

}

// "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 *----------------------------------------------------------------------*

Page 100: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 100

* *----------------------------------------------------------------------* 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.

Page 101: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 101

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

Page 102: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 102

,d2 TYPE REF TO concretedecoratorb . CREATE OBJECT c. CREATE OBJECT d1. CREATE OBJECT d2. d1->setcomponent( c ). d2->setcomponent( d1 ). d2->operation( ). ENDMETHOD. "endmethod ENDCLASS. "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();

Page 103: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 103

// 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,

Page 104: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 104

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)

{

Page 105: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 105

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 *----------------------------------------------------------------------* * *----------------------------------------------------------------------*

Page 106: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 106

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

Page 107: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 107

. 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( ).

Page 108: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 108

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.

Page 109: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 109

numofcopies = me->libraryitem->numcopies->get( ). SUBTRACT 1 FROM numofcopies. me->libraryitem->numcopies->set( numofcopies ). ENDMETHOD. "borrowitem METHOD returnitem. ENDMETHOD. "returnitem METHOD display. DATA name TYPE string. 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 = 'Spielberg' title = 'Jaws' numcopies = 23 playtime = 92. video->display( ). * 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. "endmethod ENDCLASS. "mainapp IMPLEMENTATION START-OF-SELECTION. mainapp=>main( ).

Page 110: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 110

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:

Page 111: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 111

• 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");

}

Page 112: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 112

}

// 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();

}

}

}

Page 113: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 113

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 *----------------------------------------------------------------------* * *----------------------------------------------------------------------*

Page 114: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 114

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

Page 115: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 115

,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. "endmethod ENDCLASS. "mainapp IMPLEMENTATION START-OF-SELECTION. mainapp=>main( ). OUTPUT: --------- MethodA() SubsystemOne Method SubsystemTwo Method SubsystemFour Method

Page 116: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 116

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)

Page 117: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 117

{

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))

{

Page 118: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 118

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 *----------------------------------------------------------------------* * *----------------------------------------------------------------------*

Page 119: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 119

CLASS customer IMPLEMENTATION. METHOD constructor. me->name = name. ENDMETHOD. "constructor METHOD getname. name = me->name. ENDMETHOD. "getname ENDCLASS. "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

Page 120: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 120

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( ).

Page 121: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 121

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. "iseligible ENDCLASS. "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. "endmethod ENDCLASS. "mainapp IMPLEMENTATION START-OF-SELECTION. mainapp=>main( ). OUTPUT ------------- Ann McKinsey applies for 125.000 loan Check bank for Ann McKinsey Check loans for Ann McKinsey Check credit for Ann McKinsey Ann McKinsey Has been Approved

Page 122: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 122

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.

Page 123: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 123

• 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

Page 124: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 124

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 *&

Page 125: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 125

*&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* 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 *----------------------------------------------------------------------* * *----------------------------------------------------------------------*

Page 126: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 126

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.

Page 127: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 127

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. "endmethod ENDCLASS. "mainapp IMPLEMENTATION START-OF-SELECTION. mainapp=>main( ). OUTPUT: ----------------- ConcreteFlyweight 21 ConcreteFlyweight 20 ConcreteFlyweight 19 UnsharedConcreteFlyw 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

Page 128: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 128

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

{

Page 129: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 129

protected char symbol;

protected int width;

protected int height;

protected int ascent;

protected int descent;

protected 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.

Page 130: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 130

// "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 (pointsize 11)

A (pointsize 12)

Z (pointsize 13)

Z (pointsize 14)

B (pointsize 15)

B (pointsize 16)

Z (pointsize 17)

B (pointsize 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.

Page 131: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 131

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

Page 132: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 132

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();

}

}

}

Page 133: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 133

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:

Page 134: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 134

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.

Page 135: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 135

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 + 2 = " + p.Add(4, 2));

Console.WriteLine("4 - 2 = " + p.Sub(4, 2));

Console.WriteLine("4 * 2 = " + p.Mul(4, 2));

Console.WriteLine("4 / 2 = " + p.Div(4, 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);

Page 136: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 136

double Div(double x, double y);

}

// "RealSubject"

class Math : IMath

{

public double Add(double x, double y){return x + y;}

public double Sub(double x, double y){return x - y;}

public double Mul(double x, double y){return x * y;}

public double Div(double x, double y){return x / y;}

}

// "Proxy Object"

class MathProxy : IMath

{

Math math;

public MathProxy()

{

math = new Math();

}

public double Add(double x, double y)

{

return math.Add(x,y);

}

public double Sub(double x, double y)

{

return math.Sub(x,y);

}

public double Mul(double x, double y)

{

return math.Mul(x,y);

}

public double Div(double x, double y)

{

return math.Div(x,y);

}

}

}

Output 4 + 2 = 6 4 - 2 = 2 4 * 2 = 8 4 / 2 = 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

Page 137: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 137

*& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* 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

Page 138: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 138

*----------------------------------------------------------------------* * *----------------------------------------------------------------------* 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().

Page 139: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 139

*---------------------------------------------------------- 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

Page 140: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 140

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();

Page 141: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 141

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)

{

Page 142: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 142

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 handled request 2 ConcreteHandler1 handled request 5 ConcreteHandler2 handled request 14 ConcreteHandler3 handled request 22 ConcreteHandler2 handled request 18 ConcreteHandler1 handled request 3 ConcreteHandler3 handled request 27 ConcreteHandler3 handled request 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.

Page 143: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 143

*----------------------------------------------------------------------* * 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

Page 144: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 144

*----------------------------------------------------------------------* * *----------------------------------------------------------------------* 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 *----------------------------------------------------------------------* *

Page 145: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 145

*----------------------------------------------------------------------* 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

Page 146: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 146

,t_request TYPE TABLE OF i ,request TYPE i . * create objects CREATE OBJECT h1. CREATE OBJECT h2. CREATE OBJECT h3. h1->setsuccessor( h2 ). h2->setsuccessor( h3 ). INSERT 2 INTO TABLE t_request. INSERT 5 INTO TABLE t_request. INSERT 14 INTO TABLE t_request. INSERT 22 INTO TABLE t_request. INSERT 18 INTO TABLE t_request. INSERT 3 INTO TABLE t_request. INSERT 27 INTO TABLE t_request. INSERT 20 INTO TABLE t_request. LOOP AT t_request INTO request. h1->handlerequest( request ). ENDLOOP. ENDMETHOD. "constructor ENDCLASS. "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);

Page 147: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 147

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)

Page 148: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 148

{

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

{

Page 149: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 149

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 *----------------------------------------------------------------------*

Page 150: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 150

* *----------------------------------------------------------------------* 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 *----------------------------------------------------------------------*

Page 151: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 151

* 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: <fs_amount> TYPE f ,<fs_number> 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 <fs_amount>. lv_dref = purchase->get_property( 'NUMBER' ). ASSIGN lv_dref->* TO <fs_number>. IF <fs_amount> < 10000. WRITE: / class_name, me->name, 'Approved request', <fs_number> USING EDIT MASK '____' . ELSE. IF NOT me->successor IS INITIAL. me->successor->processrequest( purchase ). ENDIF. ENDIF. ENDMETHOD. "ProcessRequest ENDCLASS. "Director IMPLEMENTATION *----------------------------------------------------------------------* * CLASS VicePresident DEFINITION *----------------------------------------------------------------------*

Page 152: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 152

* *----------------------------------------------------------------------* CLASS vicepresident DEFINITION INHERITING FROM approver. PUBLIC SECTION. METHODS: processrequest REDEFINITION. ENDCLASS. "VicePresident DEFINITION *----------------------------------------------------------------------* * CLASS VicePresident IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS vicepresident IMPLEMENTATION. METHOD processrequest. FIELD-SYMBOLS: <fs_amount> TYPE f ,<fs_number> 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 <fs_amount>. lv_dref = purchase->get_property( 'NUMBER' ). ASSIGN lv_dref->* TO <fs_number>. IF <fs_amount> < 25000. WRITE: / class_name, me->name, 'Approved request', <fs_number> 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: <fs_amount> TYPE f

Page 153: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 153

,<fs_number> 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 <fs_amount>. lv_dref = purchase->get_property( 'NUMBER' ). ASSIGN lv_dref->* TO <fs_number>. IF <fs_amount> < 100000. WRITE: / class_name, me->name, 'Approved request', <fs_number> USING EDIT MASK '____'. ELSE. WRITE: / class_name, me->name, 'Requires an executive meeting', <fs_number> 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().

Page 154: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 154

* 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. "constructor ENDCLASS. "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.

Page 155: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 155

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()

Page 156: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 156

{

// 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()");

}

}

Page 157: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 157

// "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

Page 158: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 158

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.

Page 159: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 159

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

Page 160: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 160

,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('+', 100);

user.Compute('-', 50);

user.Compute('*', 10);

user.Compute('/', 2);

// Undo 4 commands

user.Undo(4);

// Redo 3 commands

user.Redo(3);

Page 161: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 161

// 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)

Page 162: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 162

{

case '+': undo = '-'; break;

case '-': undo = '+'; break;

case '*': undo = '/'; break;

case '/': undo = '*'; break;

default : undo = ' '; 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();

}

}

}

Page 163: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 163

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 value = 100 (following + 100) Current value = 50 (following - 50) Current value = 500 (following * 10) Current value = 250 (following / 2) ---- Undo 4 levels Current value = 500 (following * 2) Current value = 50 (following / 10) Current value = 100 (following + 50) Current value = 0 (following - 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 *& *&---------------------------------------------------------------------*

Page 164: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 164

*& *& *&---------------------------------------------------------------------* 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 *----------------------------------------------------------------------* * *----------------------------------------------------------------------*

Page 165: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 165

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( ).

Page 166: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 166

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

Page 167: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 167

. DESCRIBE TABLE commands LINES count. SUBTRACT 1 FROM count. WRITE: /, / '----Redo levels ', levels. * perform redo operations WHILE i <= levels. IF current <= count. ADD 1 TO current. READ TABLE commands INDEX current INTO l_command. my_command ?= l_command. l_command->execute( ). ENDIF. ADD 1 TO i. ENDWHILE. ENDMETHOD. "redo "redo METHOD undo. DATA: i TYPE integer VALUE 0 ,l_command TYPE REF TO command ,my_command TYPE REF TO calculatorcommand . WRITE: /,/ '----Undo levels ', levels. * perform redo operations WHILE i < levels. IF current > 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 *----------------------------------------------------------

Page 168: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 168

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 ='+' operand = 100 ). user->compute( operator ='-' operand = 50 ). user->compute( operator ='*' operand = 10 ). user->compute( operator ='/' operand = 2 ). user->undo( 4 ). user->redo( 3 ). ENDMETHOD. "constructor ENDCLASS. "lcl_application IMPLEMENTATION START-OF-SELECTION. lcl_application=>run( ). Report ZDP_COMMAND_REALWORLD Current Value = 100 (following + 100 ) Current Value = 50 (following - 50 ) Current Value = 500 (following * 10 ) Current Value = 250 (following / 2 ) Undo levels 4 Current Value = 500 (following * 2 ) Current Value = 50 (following / 10 ) Current Value = 100 (following + 50 ) Current Value = 0 (following - 100 ) Redo levels 3 Current Value = 100 (following + 100 ) Current Value = 50 (following - 50 ) Current Value = 500 (following * 10 )

Page 169: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 169

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

Page 170: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 170

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

Page 171: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 171

{

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 Terminal.Interpret()

Called Nonterminal.Interpret()

Called Terminal.Interpret()

Called 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)

{

Page 172: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 172

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);

Page 173: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 173

}

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 abstract string One();

public abstract string Four();

public abstract string Five();

public abstract string Nine();

public abstract 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; }

}

Page 174: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 174

// 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)

Page 175: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 175

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

Page 176: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 176

{

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 class Iterator

{

public abstract object First();

public abstract object Next();

public abstract bool IsDone();

public abstract 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];

}

Page 177: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 177

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");

Page 178: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 178

collection[5] = new Item("Item 5");

collection[6] = new Item("Item 6");

collection[7] = new Item("Item 7");

collection[8] = new Item("Item 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()

{

Page 179: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 179

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;

}

Page 180: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 180

// 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

Page 181: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 181

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();

Page 182: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 182

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

Page 183: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 183

{

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

Page 184: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 184

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-to-one communication is implemented in the Chatroom, but would be trivial to change to one-to-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

Page 185: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 185

{

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; }

Page 186: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 186

}

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 a Beatle: Yoko to John: 'Hi John!' To a Beatle: Paul to Ringo: 'All you need is love' To a Beatle: Ringo to George: 'My sweet Lord' To a Beatle: Paul to John: 'Can't buy me love' To a non-Beatle: John to Yoko: 'My sweet love'

Page 187: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 187

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

{

Page 188: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 188

// 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"

Page 189: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 189

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();

Page 190: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 190

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;

Page 191: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 191

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"

Page 192: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 192

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.

Page 193: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 193

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

{

Page 194: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 194

// 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

Page 195: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 195

{

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

Page 196: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 196

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 price, which notifies investors

ibm.Price = 120.10;

ibm.Price = 121.00;

ibm.Price = 120.50;

ibm.Price = 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);

}

Page 197: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 197

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)

{

Page 198: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 198

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

Page 199: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 199

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);

Page 200: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 200

}

// "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

Page 201: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 201

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; }

}

Page 202: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 202

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)

Page 203: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 203

{

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)

{

Page 204: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 204

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()

{

Page 205: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 205

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);

}

Page 206: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 206

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

Page 207: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 207

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();

Page 208: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 208

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;

Page 209: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 209

// 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();

Page 210: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 210

// 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;

}

Page 211: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 211

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

Page 212: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 212

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;

Page 213: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 213

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

Page 214: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 214

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()

Page 215: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 215

{

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()

{

Page 216: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 216

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.

Page 217: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 217

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)

Page 218: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 218

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);

}

Page 219: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 219

// "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()

{

Page 220: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 220

}

}

// "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 visited by ConcreteVisitor1

ConcreteElementB visited by ConcreteVisitor1

ConcreteElementA visited by ConcreteVisitor2

ConcreteElementB visited by 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

Page 221: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 221

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)

Page 222: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 222

{

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;

Page 223: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 223

}

// 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

Page 224: 80142978 Design Patterns Abap Objects

Project: Design Pattern

Version: 1.0 Side: 224

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