Design Patterns
Implementation Of objects using design
patterns in Abap Object
Version: 1
Date: 2. Januar 2008
Project: Design Pattern
Version management
Date What has changed Sections Whom Version
01.12.2007 Creation of the document All BGS 1.0
Reference documents
Document Version Location
The Gang Of Four
Participants
Name Company Roll in the project Benny G. Sørensen BGS
Consulting ApS
Project: Design Pattern
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 82.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
Project: Design Pattern
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
Project: Design Pattern
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
Project: Design Pattern
1 Introduction
2 Design
Patterns
Design patterns are recurring solutions to software design problems you find
again and again in real-world application development. Patterns are about
design and interaction of objects, as well as providing a communication
platform concerning elegant, reusable solutions to commonly encountered
programming challenges.
These design patterns have been copied from The Gang of Four homepage.
The Gang of Four (GoF) patterns are generally considered the foundation for all
other patterns. They are categorized in three groups: Creational, Structural,
and Behavioral. Here you will find information on these important patterns.
To give you a head start, the C# source code is provided in 2 forms:
'structural'
and
'real-world'
.
Structural code uses type names as defined in the pattern definition and UML
diagrams.
Real-world code provides real-world programming situations where you may
use these patterns.
A third form,
'ABAP Object'
demonstrates design patterns that exploit SAP R/3
built-in ABAP Object’s features.
Creational Patterns
Abstract Factory Creates an instance of several families of classes Builder Separates object construction from its representation Factory Method Creates an instance of several derived classes Prototype A fully initialized instance to be copied or cloned Singleton A class of which only a single instance can exist
Structural Patterns
Adapter Match interfaces of different classes
Bridge Separates an object’s interface from its implementation Composite A tree structure of simple and composite objects Decorator Add responsibilities to objects dynamically
Project: Design Pattern
Flyweight A fine-grained instance used for efficient sharing Proxy An object representing another object
Behavioral Patterns
Chain of Resp. A way of passing a request between a chain of objects Command Encapsulate a command request as an object
Interpreter A way to include language elements in a program Iterator Sequentially access the elements of a collection Mediator Defines simplified communication between classes Memento Capture and restore an object's internal state Observer A way of notifying change to a number of classes State Alter an object's behavior when its state changes Strategy Encapsulates an algorithm inside a class
Template Method Defer the exact steps of an algorithm to a subclass Visitor Defines a new operation to a class without change
2.1 Creational Patterns
2.1.1 Abstract Factory
Creates an instance of several families of classes
2.1.1.1 Definition
Provide an interface for creating families of related or dependent objects
without specifying their concrete classes
A software design pattern, the Abstract Factory Pattern provides a way to
encapsulate a group of individual factories that have a common theme. In
normal usage, the client software would create a concrete implementation of
the abstract factory and then use the generic interfaces to create the concrete
objects that are part of the theme.
The client does not know (nor care) about which concrete objects it gets from
each of these internal factories since it uses only the generic interfaces of their
products. This pattern separates the details of implementation of a set of
Project: Design Pattern
An example of this would be an abstract factory class DocumentCreator that
provides interfaces to create a number of products (eg. createLetter() and
createResume()).
The system would have any number of derived concrete versions of the
DocumentCreator class like FancyDocumentCreator or
ModernDocumentCreator, each with a different implementation of
createLetter() and createResume() that would create a corresponding object
like FancyLetter or ModernResume. Each of these products is derived from a
simple abstract class like Letter or Resume of which the client is aware. The
client code would get an appropriate instantiation of the DocumentCreator and
call its factory methods. Each of the resulting objects would be created from
the same DocumentCreator implementation and would share a common theme
(they would all be fancy or modern objects). The client would need to know
how to handle only the abstract Letter or Resume class, not the specific
version that it got from the concrete factory.
In software development, a Factory is the location in the code at which
objects are constructed. The intent in employing the pattern is to insulate the
creation of objects from their usage. This allows for new derived types to be
introduced with no change to the code that uses the base class.
Use of this pattern makes it possible to interchange concrete classes without
changing the code that uses them, even at runtime. However, employment of
this pattern, as with similar design patterns, incurs the risk of unnecessary
complexity and extra work in the initial writing of code.
2.1.1.2 Commen Use
The factory determines the actual concrete type of object to be created, and it
is here that the object is actually created (in C++, for instance, by the new
operator). However, the factory only returns an abstract pointer to the created
concrete object
.
This insulates client code from object creation by having clients ask a factory
object to create an object of the desired abstract type and to return an
abstract pointer
to the object.
As the factory only returns an abstract pointer, the client code (which
requested the object from the factory) does not know - and is not burdened by
- the actual concrete type of the object which was just created. However, the
type of a concrete object (and hence a concrete factory) is known by the
abstract factory; for instance, the factory may read it from a configuration file.
The client has no need to specify the type, since it has already been specified
in the configuration file. In particular, this means:
Project: Design Pattern
• The client code has no knowledge whatsoever of the
concrete type
, not
needing to include any header files or
class declarations
relating to the
concrete type. The client code deals only with the abstract type. Objects
of a concrete type are indeed created by the factory, but the client code
accesses such objects only through their abstract interface.
• Adding new concrete types is done by modifying the client code to use a
different factory, a modification which is typically one line in one file.
(The different factory then creates objects of a different concrete type,
but still returns a pointer of the same abstract type as before - thus
insulating the client code from change.) This is significantly easier than
modifying the client code to instantiate a new type, which would require
changing every location in the code where a new object is created (as
well as making sure that all such code locations also have knowledge of
the new concrete type, by including for instance a concrete class header
file). If all factory objects are stored globally in a singleton object, and all
client code goes through the singleton to access the proper factory for
object creation, then changing factories is as easy as changing the
singleton object.
Project: Design Pattern
2.1.1.3 UML class diagram
2.1.1.4 Participants
The classes and/or objects participating in this pattern are:
•
AbstractFactory
(ContinentFactory)
declares an interface for operations that create abstract products
•
ConcreteFactory
(AfricaFactory, AmericaFactory)
implements the operations to create concrete product objects
•
AbstractProduct
(Herbivore, Carnivore)
declares an interface for a type of product object
•
Product
(Wildebeest, Lion, Bison, Wolf)
defines a product object to be created by the corresponding concrete
factory implements the AbstractProduct interface
•
Client
(AnimalWorld)
uses interfaces declared by AbstractFactory and AbstractProduct classes
2.1.1.5 Sample code in C#
This
structural
code demonstrates the Abstract Factory pattern creating
parallel hierarchies of objects. Object creation has been abstracted and there is
no need for hard-coded class names in the client code.
Project: Design Pattern
using System;namespace DoFactory.GangOfFour.Abstract.Structural {
// MainApp test application class MainApp
{
public static void Main() {
// Abstract factory #1
AbstractFactory factory1 = new ConcreteFactory1(); Client c1 = new Client(factory1);
c1.Run();
// Abstract factory #2
AbstractFactory factory2 = new ConcreteFactory2(); Client c2 = new Client(factory2);
c2.Run();
// Wait for user input Console.Read();
} }
// "AbstractFactory"
abstract class AbstractFactory {
public abstract AbstractProductA CreateProductA(); public abstract AbstractProductB CreateProductB(); }
// "ConcreteFactory1"
class ConcreteFactory1 : AbstractFactory {
public override AbstractProductA CreateProductA() {
return new ProductA1(); }
public override AbstractProductB CreateProductB() {
return new ProductB1(); }
}
// "ConcreteFactory2"
class ConcreteFactory2 : AbstractFactory {
public override AbstractProductA CreateProductA() {
return new ProductA2(); }
Project: Design Pattern
{return new ProductB2(); }
}
// "AbstractProductA"
abstract class AbstractProductA {
}
// "AbstractProductB"
abstract class AbstractProductB {
public abstract void Interact(AbstractProductA a); }
// "ProductA1"
class ProductA1 : AbstractProductA {
}
// "ProductB1"
class ProductB1 : AbstractProductB {
public override void Interact(AbstractProductA a) {
Console.WriteLine(this.GetType().Name + " interacts with " + a.GetType().Name); }
}
// "ProductA2"
class ProductA2 : AbstractProductA {
}
// "ProductB2"
class ProductB2 : AbstractProductB {
public override void Interact(AbstractProductA a) {
Console.WriteLine(this.GetType().Name + " interacts with " + a.GetType().Name); }
}
// "Client" - the interaction environment of the products class Client
Project: Design Pattern
private AbstractProductA AbstractProductA; private AbstractProductB AbstractProductB; // Constructor
public Client(AbstractFactory factory) {
AbstractProductB = factory.CreateProductB(); AbstractProductA = factory.CreateProductA(); }
public void Run() { AbstractProductB.Interact(AbstractProductA); } } } Output
ProductB1 interacts with ProductA1 ProductB2 interacts with ProductA2
2.1.1.6 Sample code in ABAP
This
structural
code demonstrates the Abstract Factory pattern creating
parallel hierarchies of objects. Object creation has been abstracted and there is
no need for hard-coded class names in the client code. In ABAP you should
consider using interfaces instead of abstract classes.
REPORT ZABSTRACTFACTORY_STRUCTURAL NO STANDARD PAGE HEADING LINE-SIZE 80. CLASS cl_abap_typedescr DEFINITION LOAD.
DATA: moff TYPE i ,slen TYPE i ,mlen TYPE i. DEFINE ?get_class_name.
&2 = cl_abap_classdescr=>get_class_name( &1 ).
find regex 'CLASS=' in &2 match offset moff match length mlen. slen = moff + mlen.
shift &2 by slen places left. END-OF-DEFINITION.
CLASS abstractproducta DEFINITION ABSTRACT.
ENDCLASS. "abstractproducta DEFINITION CLASS abstractproductb DEFINITION ABSTRACT.
PUBLIC SECTION. METHODS:
interact ABSTRACT IMPORTING a TYPE REF TO abstractproducta . ENDCLASS. "abstractproductb DEFINITION
CLASS abstractproductb IMPLEMENTATION.
ENDCLASS. "abstractproductb IMPLEMENTATION CLASS producta1 DEFINITION INHERITING FROM abstractproducta. ENDCLASS. "producta1 DEFINITION
Project: Design Pattern
PUBLIC SECTION.METHODS:
interact REDEFINITION.
ENDCLASS. "productb1 DEFINITION CLASS productb1 IMPLEMENTATION.
METHOD interact.
DATA: class_name_me TYPE abap_abstypename ,class_name_a TYPE abap_abstypename. ?get_class_name me class_name_me. ?get_class_name a class_name_a. WRITE: / class_name_me ,'Interact with ' ,class_name_a. ENDMETHOD. "interact
ENDCLASS. "productb1 IMPLEMENTATION CLASS producta2 DEFINITION INHERITING FROM abstractproducta. ENDCLASS. "producta2 DEFINITION
CLASS productb2 DEFINITION INHERITING FROM abstractproductb. PUBLIC SECTION.
METHODS:
interact REDEFINITION.
ENDCLASS. "productb2 DEFINITION CLASS productb2 IMPLEMENTATION.
METHOD interact.
DATA: class_name_me TYPE abap_abstypename ,class_name_a TYPE abap_abstypename. ?get_class_name me class_name_me. ?get_class_name a class_name_a. WRITE: / class_name_me ,'Interact with ' ,class_name_a. ENDMETHOD. "interact
ENDCLASS. "productb2 IMPLEMENTATION CLASS abstractfactory DEFINITION ABSTRACT.
PUBLIC SECTION. METHODS:
createproducta ABSTRACT RETURNING value(producta) TYPE REF TO abstractproducta ,createproductb ABSTRACT RETURNING value(productb) TYPE REF TO abstractproductb .
ENDCLASS. "abstractfactory DEFINITION
CLASS concretefactory1 DEFINITION INHERITING FROM abstractfactory. PUBLIC SECTION.
METHODS:
createproducta REDEFINITION ,createproductb REDEFINITION .
ENDCLASS. "concretefactory1 DEFINITION CLASS concretefactory1 IMPLEMENTATION.
METHOD createproducta.
CREATE OBJECT producta TYPE producta1. ENDMETHOD. "createproducta METHOD createproductb.
CREATE OBJECT productb TYPE productb1. ENDMETHOD. "createproductb
ENDCLASS. "concretefactory1 IMPLEMENTATION CLASS concretefactory2 DEFINITION INHERITING FROM abstractfactory. PUBLIC SECTION.
Project: Design Pattern
METHODS:createproducta REDEFINITION ,createproductb REDEFINITION .
ENDCLASS. "concretefactory2 DEFINITION CLASS concretefactory2 IMPLEMENTATION.
METHOD createproducta.
CREATE OBJECT producta TYPE producta2. ENDMETHOD. "createproducta METHOD createproductb.
CREATE OBJECT productb TYPE productb2. ENDMETHOD. "createproductb
ENDCLASS. "concretefactory1 IMPLEMENTATION CLASS client DEFINITION.
PUBLIC SECTION. METHODS:
constructor IMPORTING factory TYPE REF TO abstractfactory ,run
.
PROTECTED SECTION.
DATA: abstractproducta TYPE REF TO abstractproducta ,abstractproductb TYPE REF TO abstractproductb .
ENDCLASS. "client DEFINITION CLASS client IMPLEMENTATION.
METHOD constructor. abstractproducta = factory->createproducta( ). abstractproductb = factory->createproductb( ). ENDMETHOD. "constructor METHOD run. abstractproductb->interact( abstractproducta ). ENDMETHOD. "run
ENDCLASS. "client IMPLEMENTATION CLASS mainapp DEFINITION.
PUBLIC SECTION.
* CLASS-DATA: oa_creator_coll TYPE TABLE OF REF TO creator. CLASS-METHODS main.
ENDCLASS. "mainapp DEFINITION CLASS mainapp IMPLEMENTATION.
METHOD main.
DATA: factory1 TYPE REF TO 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.
Project: Design Pattern
Output PRODUCTB1 Interact with PRODUCTA1 PRODUCTB2 Interact with PRODUCTA22.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() {
Project: Design Pattern
return new Wildebeest(); }public override Carnivore CreateCarnivore() {
return new Lion(); }
}
// "ConcreteFactory2"
class AmericaFactory : ContinentFactory {
public override Herbivore CreateHerbivore() {
return new Bison(); }
public override Carnivore CreateCarnivore() {
return new Wolf(); }
}
// "AbstractProductA" abstract class Herbivore {
}
// "AbstractProductB" abstract class Carnivore {
public abstract void Eat(Herbivore h); }
// "ProductA1"
class Wildebeest : Herbivore {
}
// "ProductB1"
class Lion : Carnivore {
public override void Eat(Herbivore h) { // Eat Wildebeest Console.WriteLine(this.GetType().Name + " eats " + h.GetType().Name); } } // "ProductA2"
Project: Design Pattern
{}
// "ProductB2"
class Wolf : Carnivore {
public override void Eat(Herbivore h) { // Eat Bison Console.WriteLine(this.GetType().Name + " eats " + h.GetType().Name); } } // "Client" class AnimalWorld {
private Herbivore herbivore; private Carnivore carnivore; // Constructor
public AnimalWorld(ContinentFactory factory) {
carnivore = factory.CreateCarnivore(); herbivore = factory.CreateHerbivore(); }
public void RunFoodChain() { carnivore.Eat(herbivore); } } } Output
Lion eats Wildebeest Wolf eats Bison
2.1.1.8 Sample code in ABAP
This
real-world
code demonstrates the creation of different animal worlds for a
computer game using different factories. Although the animals created by the
Continent factories are different, the interactions among the animals remain
the same. You should however consider using interfaces instead of abstract
classes.
REPORT zabstractfactory_realworld NO STANDARD PAGE HEADING LINE-SIZE 80. CLASS cl_abap_typedescr DEFINITION LOAD.
DATA: moff TYPE i ,slen TYPE i ,mlen TYPE i. DEFINE ?get_class_name.
Project: Design Pattern
&2 = cl_abap_classdescr=>get_class_name( &1 ).
find regex 'CLASS=' in &2 match offset moff match length mlen. slen = moff + mlen.
shift &2 by slen places left. END-OF-DEFINITION.
CLASS herbivore DEFINITION ABSTRACT.
ENDCLASS. "herbivore DEFINITION CLASS carnivore DEFINITION ABSTRACT.
PUBLIC SECTION. METHODS:
eat ABSTRACT IMPORTING a TYPE REF TO herbivore . ENDCLASS. "carnivore DEFINITION CLASS carnivore IMPLEMENTATION.
ENDCLASS. "carnivore IMPLEMENTATION CLASS wildebeest DEFINITION INHERITING FROM herbivore. ENDCLASS. "wildebeest DEFINITION CLASS lion DEFINITION INHERITING FROM carnivore. PUBLIC SECTION.
METHODS:
eat REDEFINITION.
ENDCLASS. "Lion DEFINITION CLASS lion IMPLEMENTATION.
METHOD eat.
DATA: class_name_me TYPE abap_abstypename ,class_name_a TYPE abap_abstypename. ?get_class_name me class_name_me. ?get_class_name a class_name_a. WRITE: / class_name_me ,' eats ' ,class_name_a. ENDMETHOD. "interact
ENDCLASS. "Lion IMPLEMENTATION CLASS bison DEFINITION INHERITING FROM herbivore. ENDCLASS. "Bison DEFINITION CLASS wolf DEFINITION INHERITING FROM carnivore. PUBLIC SECTION.
METHODS:
eat REDEFINITION.
ENDCLASS. "Wolf DEFINITION CLASS wolf IMPLEMENTATION.
METHOD eat.
DATA: class_name_me TYPE abap_abstypename ,class_name_a TYPE abap_abstypename. ?get_class_name me class_name_me. ?get_class_name a class_name_a. WRITE: / class_name_me ,' eats ' ,class_name_a. ENDMETHOD. "interact
ENDCLASS. "Wolf IMPLEMENTATION CLASS continentfactory DEFINITION ABSTRACT. PUBLIC SECTION.
METHODS:
createherbivore ABSTRACT RETURNING value(herbivore) TYPE REF TO herbivore ,createcarnivore ABSTRACT RETURNING value(carnivore) TYPE REF TO carnivore .
Project: Design Pattern
ENDCLASS. "ContinentFactory DEFINITION
CLASS africafactory DEFINITION INHERITING FROM continentfactory. PUBLIC SECTION.
METHODS:
createherbivore REDEFINITION ,createcarnivore REDEFINITION .
ENDCLASS. "ContinentFactory DEFINITION CLASS africafactory IMPLEMENTATION.
METHOD createherbivore.
CREATE OBJECT herbivore TYPE wildebeest. ENDMETHOD. "createproducta METHOD createcarnivore.
CREATE OBJECT carnivore TYPE lion.
ENDMETHOD. "createproductb
ENDCLASS. "ContinentFactory IMPLEMENTATION
CLASS americafactory DEFINITION INHERITING FROM continentfactory. PUBLIC SECTION.
METHODS:
createherbivore REDEFINITION ,createcarnivore REDEFINITION .
ENDCLASS. "concretefactory2 DEFINITION CLASS americafactory IMPLEMENTATION.
METHOD createherbivore.
CREATE OBJECT herbivore TYPE bison.
ENDMETHOD. "createproducta METHOD createcarnivore.
CREATE OBJECT carnivore TYPE wolf.
ENDMETHOD. "createproductb
ENDCLASS. "ContinentFactory IMPLEMENTATION CLASS animalworld DEFINITION.
PUBLIC SECTION. METHODS:
constructor IMPORTING factory TYPE REF TO continentfactory ,runfoodchain
.
PROTECTED SECTION.
DATA: herbivore TYPE REF TO herbivore ,carnivore TYPE REF TO carnivore .
ENDCLASS. "Animalworld DEFINITION CLASS animalworld IMPLEMENTATION.
METHOD constructor. herbivore = factory->createherbivore( ). carnivore = factory->createcarnivore( ). ENDMETHOD. "constructor METHOD runfoodchain. carnivore->eat( herbivore ). ENDMETHOD. "Runfoodchain
ENDCLASS. "Animalworld IMPLEMENTATION CLASS mainapp DEFINITION.
PUBLIC SECTION. CLASS-METHODS main.
Project: Design Pattern
CLASS mainapp IMPLEMENTATION. METHOD main.
DATA: africa TYPE REF TO africafactory ,america TYPE REF TO americafactory ,world TYPE REF TO animalworld .
CREATE OBJECT africa.
CREATE OBJECT world EXPORTING factory = africa . CALL METHOD world->runfoodchain( ).
CREATE OBJECT america.
CREATE OBJECT world EXPORTING factory = america. CALL METHOD world->runfoodchain( ).
ENDMETHOD. "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
Project: Design Pattern
Abstract Factory is concerned, the product gets returned immediately.
• Builder often builds a Composite.
• Often, designs start out using Factory Method (less complicated, more
customizable, subclasses proliferate) and evolve toward Abstract Factory,
Prototype, or Builder (more flexible, more complex) as the designer
discovers where more flexibility is needed.
2.1.2.3 UML class diagram
2.1.2.4 Participants
The classes and/or objects participating in this pattern are:
•
Builder
(VehicleBuilder)
o
specifies an abstract interface for creating parts of a Product object
•
ConcreteBuilder
(MotorCycleBuilder, CarBuilder, ScooterBuilder)
o
constructs and assembles parts of the product by implementing the
Builder interface defines and keeps track of the representation it
creates provides an interface for retrieving the product
•
Director
(Shop)
o
constructs an object using the Builder interface
•
Product
(Vehicle)
o
represents the complex object under construction. ConcreteBuilder
builds the product's internal representation and defines the process
by which it's assembled includes classes that define the constituent
parts, including interfaces for assembling the parts into the final
result
2.1.2.5 Sample code In C#
This
structural
code demonstrates the Builder pattern in which complex objects
are created in a step-by-step fashion. The construction process can create
different object representations and provides a high level of control over the
assembly of the objects.
Project: Design Pattern
using System;
using System.Collections;
namespace DoFactory.GangOfFour.Builder.Structural {
// MainApp test application public class MainApp
{
public static void Main() {
// Create director and builders Director director = new Director(); Builder b1 = new ConcreteBuilder1(); Builder b2 = new ConcreteBuilder2(); // Construct two products
director.Construct(b1); Product p1 = b1.GetResult(); p1.Show(); director.Construct(b2); Product p2 = b2.GetResult(); p2.Show();
// Wait for user Console.Read(); } } // "Director" class Director {
// Builder uses a complex series of steps public void Construct(Builder builder) { builder.BuildPartA(); builder.BuildPartB(); } } // "Builder"
abstract class Builder {
public abstract void BuildPartA(); public abstract void BuildPartB(); public abstract Product GetResult(); }
// "ConcreteBuilder1"
Project: Design Pattern
{private Product product = new Product(); public override void BuildPartA()
{
product.Add("PartA"); }
public override void BuildPartB() {
product.Add("PartB"); }
public override Product GetResult() {
return product; }
}
// "ConcreteBuilder2"
class ConcreteBuilder2 : Builder {
private Product product = new Product(); public override void BuildPartA()
{
product.Add("PartX"); }
public override void BuildPartB() {
product.Add("PartY"); }
public override Product GetResult() { return product; } } // "Product" class Product {
ArrayList parts = new ArrayList(); public void Add(string part) {
parts.Add(part); }
public void Show() {
Console.WriteLine("\nProduct Parts ---"); foreach (string part in parts)
Project: Design Pattern
Console.WriteLine(part); } } } Output Product Parts --- PartA PartB Product Parts --- PartX PartY2.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
Project: Design Pattern
.PRIVATE SECTION.
DATA: product TYPE REF TO product.
ENDCLASS. "concretebuilder1 DEFINITION CLASS concretebuilder1 IMPLEMENTATION.
METHOD constructor.
CALL METHOD super->constructor. CREATE OBJECT me->product.
ENDMETHOD. "constructor METHOD buildparta. product->add('PartA'). ENDMETHOD. "buildparta METHOD buildpartb. product->add('Partb'). ENDMETHOD. "buildpartb METHOD getresult. product = me->product. ENDMETHOD. "getresult
ENDCLASS. "concretebuilder1 IMPLEMENTATION CLASS concretebuilder2 DEFINITION INHERITING FROM builder. PUBLIC SECTION. METHODS: constructor ,buildparta REDEFINITION ,buildpartb REDEFINITION ,getresult REDEFINITION . PRIVATE SECTION.
DATA: product TYPE REF TO product.
ENDCLASS. "concretebuilder2 DEFINITION CLASS concretebuilder2 IMPLEMENTATION.
METHOD constructor.
CALL METHOD super->constructor. CREATE OBJECT me->product.
ENDMETHOD. "constructor METHOD buildparta. product->add('PartX'). ENDMETHOD. "buildparta METHOD buildpartb. product->add('PartY'). ENDMETHOD. "buildpartb METHOD getresult. product = me->product. ENDMETHOD. "getresult
ENDCLASS. "concretebuilder2 IMPLEMENTATION CLASS director DEFINITION.
PUBLIC SECTION. METHODS:
construct IMPORTING builder TYPE REF TO builder. ENDCLASS. "director DEFINITION CLASS director IMPLEMENTATION.
METHOD construct.
builder->buildparta( ). builder->buildpartb( ).
ENDMETHOD. "construct
ENDCLASS. "director IMPLEMENTATION CLASS mainapp DEFINITION.
PUBLIC SECTION.
CLASS-DATA: oa_creator_coll TYPE TABLE OF REF TO creator. CLASS-METHODS main.
Project: Design Pattern
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();
Project: Design Pattern
VehicleBuilder b1 = new ScooterBuilder(); VehicleBuilder b2 = new CarBuilder();
VehicleBuilder b3 = new MotorCycleBuilder(); // Construct and display vehicles
shop.Construct(b1); b1.Vehicle.Show(); shop.Construct(b2); b2.Vehicle.Show(); shop.Construct(b3); b3.Vehicle.Show(); // Wait for user Console.Read(); } } // "Director" class Shop {
// Builder uses a complex series of steps
public void Construct(VehicleBuilder vehicleBuilder) { vehicleBuilder.BuildFrame(); vehicleBuilder.BuildEngine(); vehicleBuilder.BuildWheels(); vehicleBuilder.BuildDoors(); } } // "Builder"
abstract class VehicleBuilder {
protected Vehicle vehicle; // Property
public Vehicle Vehicle {
get{ return vehicle; } }
public abstract void BuildFrame(); public abstract void BuildEngine(); public abstract void BuildWheels(); public abstract void BuildDoors(); }
// "ConcreteBuilder1"
class MotorCycleBuilder : VehicleBuilder {
Project: Design Pattern
{vehicle = new Vehicle("MotorCycle"); vehicle["frame"] = "MotorCycle Frame"; }
public override void BuildEngine() {
vehicle["engine"] = "500 cc"; }
public override void BuildWheels() {
vehicle["wheels"] = "2"; }
public override void BuildDoors() {
vehicle["doors"] = "0"; }
}
// "ConcreteBuilder2"
class CarBuilder : VehicleBuilder {
public override void BuildFrame() {
vehicle = new Vehicle("Car"); vehicle["frame"] = "Car Frame"; }
public override void BuildEngine() {
vehicle["engine"] = "2500 cc"; }
public override void BuildWheels() {
vehicle["wheels"] = "4"; }
public override void BuildDoors() {
vehicle["doors"] = "4"; }
}
// "ConcreteBuilder3"
class ScooterBuilder : VehicleBuilder {
public override void BuildFrame() {
vehicle = new Vehicle("Scooter"); vehicle["frame"] = "Scooter Frame"; }
Project: Design Pattern
public override void BuildEngine() {
vehicle["engine"] = "50 cc"; }
public override void BuildWheels() {
vehicle["wheels"] = "2"; }
public override void BuildDoors() { vehicle["doors"] = "0"; } } // "Product" class Vehicle {
private string type;
private Hashtable parts = new Hashtable(); // Constructor
public Vehicle(string type) {
this.type = type; }
// Indexer (i.e. smart array) public object this[string key] {
get{ return parts[key]; } set{ parts[key] = value; } }
public void Show() {
Console.WriteLine("\n---"); Console.WriteLine("Vehicle Type: {0}", type); Console.WriteLine(" Frame : {0}", parts["frame"]); Console.WriteLine(" Engine : {0}", parts["engine"]); Console.WriteLine(" #Wheels: {0}", parts["wheels"]); Console.WriteLine(" #Doors : {0}", parts["doors"]); }
} }
Output
--- Vehicle Type: Scooter Frame : Scooter Frame Engine : none
#Wheels: 2 #Doors : 0
Project: Design Pattern
--- Vehicle Type: Car
Frame : Car Frame Engine : 2500 cc #Wheels: 4 #Doors : 4
--- Vehicle Type: MotorCycle Frame : MotorCycle Frame Engine : 500 cc
#Wheels: 2 #Doors : 0
2.1.2.8 Sample code In ABAP
This
real-world
code demonstates the Builder pattern in which different
vehicles are assembled in a step-by-step fashion. The Shop uses
VehicleBuilders to construct a variety of Vehicles in a series of sequential
steps.
REPORT zbuilder_realworld NO STANDARD PAGE HEADING LINE-SIZE 80. CLASS vehicle DEFINITION.
PUBLIC SECTION.
TYPES: ty_key(30) TYPE c ,ty_part(30) TYPE c ,BEGIN OF ty_parts ,key TYPE ty_key ,part TYPE ty_part ,END OF ty_parts. METHODS:
constructor IMPORTING vtype TYPE string ,add IMPORTING key TYPE ty_key
part TYPE ty_part ,show.
PRIVATE SECTION.
DATA: parts TYPE HASHED TABLE OF ty_parts WITH UNIQUE KEY key
,vtype(30) TYPE c.
ENDCLASS. "Vehicle DEFINITION CLASS vehicle IMPLEMENTATION.
METHOD constructor. me->vtype = vtype.
ENDMETHOD. "constructor METHOD add.
DATA: buffer TYPE ty_parts. buffer-key = key.
buffer-part = part.
INSERT buffer INTO TABLE parts. ENDMETHOD. "add METHOD show.
DATA: parts_line TYPE ty_parts.
write: / '---'. WRITE: / 'Vehicle Type:' , vtype.
LOOP AT parts INTO parts_line.
WRITE: / parts_line-key, parts_line-part. ENDLOOP.
Project: Design Pattern
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
Project: Design Pattern
,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( ).
Project: Design Pattern
vehiclebuilder->buildwheels( ). vehiclebuilder->builddoors( ).
ENDMETHOD. "construct
ENDCLASS. "shop IMPLEMENTATION CLASS mainapp DEFINITION.
PUBLIC SECTION.
CLASS-DATA: oa_creator_coll TYPE TABLE OF REF TO creator. CLASS-METHODS main.
ENDCLASS. "mainapp DEFINITION CLASS mainapp IMPLEMENTATION.
METHOD main.
DATA: shop TYPE REF TO shop
,b1 TYPE REF TO scooterbuilder ,b2 TYPE REF TO carbuilder
,b3 TYPE REF TO motorcyclebuilder .
* Create shop with vehiclle builders CREATE OBJECT shop.
CREATE OBJECT b1 EXPORTING vtype = 'Scooter'. CREATE OBJECT b2 EXPORTING vtype = 'Car'.
CREATE OBJECT b3 EXPORTING vtype = 'MotorCycle'. * Construct and display vehicles
CALL METHOD shop->construct( b1 ). b1->show( ).
CALL METHOD shop->construct( b2 ). b2->show( ).
CALL METHOD shop->construct( b3 ). b3->show( ).
ENDMETHOD. "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.
Project: Design Pattern
2.1.3.2 UML class diagram
The product is a
generelization
of the concrete product, like the creator is a
generelization
of the spacialized concretecreator. The ConcreteCreator have
dependency
off Product Class
2.1.3.3 Participants
The classes and/or objects participating in this pattern are:
o
Product
(Page)
o
defines the interface of objects the factory method creates
o
ConcreteProduct
(SkillsPage, EducationPage, ExperiencePage)
o
implements the Product interface
o
Creator
(Document)
o
declares the factory method, which returns an object of type
Product. Creator may also define a default implementation of the
factory method that returns a default ConcreteProduct object. may
call the factory method to create a Product object.
o
ConcreteCreator
(Report, Resume)
o
overrides the factory method to return an instance of a
ConcreteProduct.
2.1.3.4 Sample code In C#
This
structural
code demonstrates the Factory method offering great flexibility
in creating different objects. The Abstract class may provide a default object,
but each subclass can instantiate an extended version of the object.
// Factory Method pattern -- Structural example using System;
using System.Collections;
namespace DoFactory.GangOfFour.Factory.Structural {
Project: Design Pattern
class MainApp {
static void Main() {
// An array of creators
Creator[] creators = new Creator[2]; creators[0] = new ConcreteCreatorA(); creators[1] = new ConcreteCreatorB();
// Iterate over creators and create products foreach(Creator creator in creators)
{
Product product = creator.FactoryMethod(); Console.WriteLine("Created {0}",
product.GetType().Name); }
// Wait for user Console.Read(); }
}
// "Product"
abstract class Product {
}
// "ConcreteProductA"
class ConcreteProductA : Product {
}
// "ConcreteProductB"
class ConcreteProductB : Product {
}
// "Creator"
abstract class Creator {
public abstract Product FactoryMethod(); }
// "ConcreteCreator"
class ConcreteCreatorA : Creator {
public override Product FactoryMethod() {
return new ConcreteProductA(); }
Project: Design Pattern
}// "ConcreteCreator"
class ConcreteCreatorB : Creator {
public override Product FactoryMethod() {
return new ConcreteProductB(); } } } Output Created ConcreteProductA Created ConcreteProductB
This
real-world
code demonstrates the Factory method offering flexibility in
creating different documents. The derived Document classes Report and
Resume instantiate extended versions of the Document class. Here, the
Factory Method is called in the constructor of the Document base class.
// Factory Method pattern -- Real World exampleusing 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(); }
Project: Design Pattern
// "Product"
abstract class Page {
}
// "ConcreteProduct" class SkillsPage : Page {
}
// "ConcreteProduct" class EducationPage : Page {
}
// "ConcreteProduct"
class ExperiencePage : Page {
}
// "ConcreteProduct"
class IntroductionPage : Page {
}
// "ConcreteProduct" class ResultsPage : Page {
}
// "ConcreteProduct"
class ConclusionPage : Page {
}
// "ConcreteProduct" class SummaryPage : Page {
}
// "ConcreteProduct"
class BibliographyPage : Page {
}
Project: Design Pattern
abstract class Document {
private ArrayList pages = new ArrayList(); // Constructor calls abstract Factory method public Document()
{
this.CreatePages(); }
public ArrayList Pages {
get{ return pages; } }
// Factory Method
public abstract void CreatePages(); }
// "ConcreteCreator" class Resume : Document {
// Factory Method implementation public override void CreatePages() { Pages.Add(new SkillsPage()); Pages.Add(new EducationPage()); Pages.Add(new ExperiencePage()); } } // "ConcreteCreator" class Report : Document {
// Factory Method implementation public override void CreatePages() { Pages.Add(new IntroductionPage()); Pages.Add(new ResultsPage()); Pages.Add(new ConclusionPage()); Pages.Add(new SummaryPage()); Pages.Add(new BibliographyPage()); } } } Output Resume --- SkillsPage EducationPage ExperiencePage Report --- IntroductionPage
Project: Design Pattern
ResultsPageConclusionPage 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
Project: Design Pattern
CLASS creator DEFINITION ABSTRACT. PUBLIC SECTION.
METHODS:
factorymethod ABSTRACT RETURNING value(product) TYPE REF TO product. ENDCLASS. "product DEFINITION
CLASS concretecreatora DEFINITION INHERITING FROM creator. PUBLIC SECTION.
METHODS:
factorymethod REDEFINITION.
ENDCLASS. "concretecreatora DEFINITION CLASS concretecreatora IMPLEMENTATION.
METHOD factorymethod.
CREATE OBJECT product TYPE concreteproducta. ENDMETHOD. "factoryproduct
ENDCLASS. "concretecreatora IMPLEMENTATION CLASS concretecreatorb DEFINITION INHERITING FROM creator. PUBLIC SECTION.
METHODS:
factorymethod REDEFINITION.
ENDCLASS. "concretecreatorb DEFINITION CLASS concretecreatorb IMPLEMENTATION.
METHOD factorymethod.
CREATE OBJECT product TYPE concreteproductb. ENDMETHOD. "factoryproduct
ENDCLASS. "concretecreatorb IMPLEMENTATION CLASS mainapp DEFINITION.
PUBLIC SECTION.
CLASS-DATA: oa_creator_coll TYPE TABLE OF REF TO creator. CLASS-METHODS main.
ENDCLASS. "mainapp DEFINITION CLASS mainapp IMPLEMENTATION.
METHOD main.
DATA: creator TYPE REF TO creator
,concretecreatora TYPE REF TO concretecreatora ,concretecreatorb TYPE REF TO concretecreatorb ,product TYPE REF TO product
,class_name TYPE abap_abstypename .
FIELD-SYMBOLS <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.
Project: Design Pattern
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.
Project: Design Pattern
PUBLIC SECTION.INTERFACES: product.
ENDCLASS. "concreteproductB DEFINITION CLASS concreteproductb IMPLEMENTATION.
METHOD product~get_name. name = 'ConCreteProductB'.
ENDMETHOD. "product~getname
ENDCLASS. "concreteproductB IMPLEMENTATION INTERFACE creator.
METHODS:
factorymethod RETURNING value(product) TYPE REF TO product. ENDINTERFACE.
CLASS concretecreatora DEFINITION. PUBLIC SECTION.
INTERFACES: creator.
ENDCLASS. "concretecreatora DEFINITION CLASS concretecreatora IMPLEMENTATION.
METHOD creator~factorymethod.
CREATE OBJECT product TYPE concreteproducta. ENDMETHOD. "factoryproduct
ENDCLASS. "concretecreatora IMPLEMENTATION CLASS concretecreatorb DEFINITION.
PUBLIC SECTION. INTERFACES: creator.
ENDCLASS. "concretecreatorb DEFINITION CLASS concretecreatorb IMPLEMENTATION.
METHOD creator~factorymethod.
CREATE OBJECT product TYPE concreteproductb. ENDMETHOD. "factoryproduct
ENDCLASS. "concretecreatorb IMPLEMENTATION CLASS mainapp DEFINITION.
PUBLIC SECTION.
CLASS-DATA: oa_creator_coll TYPE TABLE OF REF TO creator. CLASS-METHODS main.
ENDCLASS. "mainapp DEFINITION CLASS mainapp IMPLEMENTATION.
METHOD main.
data: concretecreatora TYPE 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.