Sie sind auf Seite 1von 54

Design Patterns

Christopher Alexander says, “Each pattern describes a problem which occurs over and
over again in our environment, and then describes the core of the solution to
that problem, in such a way that you can use this solution a million times over,
without ever doing it the same way twice.” Though he speaks about the
buildings and towns, the same can be applied to object-oriented design
patterns.
If a problem occurs over and over again, the solution to the problem is used effectively.
Such solution is known as a pattern. The design patterns are language independent
strategies used to provide a solution for any object oriented design problems.

Different Defns:
1. Design patterns are solutions to the recurring design problems.
2. Design patterns constitute a set of rules describing how to accomplish certain tasks in
the realm of software development.
3. Design patterns focus more on reuse of recurring architectural design themes, while
frameworks focus on detailed design and implementation.
4. Patterns identify and specify abstractions that are above the level of single classes and
instances, or of components.
The design patterns are discovered rather than written. The process of finding out these
patterns is called “pattern mining”.

Design patterns are descriptions of communication between objects and classes


that are customized to solve a general design problem in a particular context. A
design pattern names, abstracts and identifies the main aspects of a common
design structure that make it useful for creating a reusable object-oriented
design. It identified the participating classes and interfaces, their roles and
collaboration and the distribution of responsibilities. Each pattern focuses on a
particular design problem or issue. It describes when it applies and whether it
can be applied in view of other design constraints. It also describes the
consequences and the trade-offs of its use. A design pattern has four elements:
1. The pattern name: It can be used to describe a design problem, its solutions and
consequences in a word or two. It makes it easier to think about designs and
communicate them and their trade-offs to others easily.
2. The problem: The problem describes when the pattern can be applied. It explains the
context of use for the pattern. It might also describe the class or object
structures that are symptoms of poor designs. It might also include a set of
conditions that must be met to apply the pattern.
3. The solution: The solution describes the elements of the pattern that make up the
design. It also describes the structure of the pattern i.e the relationships,
responsibilities and the collaboration between different elements of the pattern.
It basically gives the template that can be applied in different situations.
4. The consequences: These are the results and trade-offs that occur due to the usage of
the pattern. They are useful in choosing an alternative pattern. They also help

1
in evaluating the benefits and costs involved in using the pattern. The
consequences for s/w often concern space and time trade-offs.

Classification of Design Patterns:


Design patterns vary in their granularity and level of abstraction. The design patterns can
be classified by two criteria:
1. Purpose.
2. Scope.

By purpose, the design patterns can be classified into:

Creational patterns: They concern the process of object creation.


Structural patterns: They deal with the composition of classes or objects.
Behavioral patterns: They characterize the ways in which classes or objects interact and
distribute responsibility.

By scope, the design patterns can be classified into:


Class patterns: They deal with the relationships between classes and their subclasses.
These relationships are established through inheritance, so they are static-fixed
at compile-time.
Object patterns: They deal with the object relationships, which can be changed at run-
time and are more dynamic.

The creational class patterns defer some part of the object creation to subclasses, and
object creational patterns defer it to another object. The structural class
patterns use inheritance to compose classes whereas the structural object
patterns describe ways to assemble objects. The behavioral class patterns use
inheritance to describe algorithms and flow of control, whereas the behavioral
object patterns describe how a group of objects cooperate to perform a task that
no single object can carry out alone.
The different design patterns catalog grouped into different categories is as follows:

PURPOSE:

1. Abstract factory
2. Builder
Creational Patterns 3. Factory Method
4. Prototype
5. Singleton

1. Adapter
2. Bridge
3. Composite
Structural Patterns 4. Decorator
5. Façade

2
6. Flyweight
7. Proxy

1. Chain of Responsibility
2. Command
3. Interpreter
Behavioral 4. Iterator
5. Mediator
6. Memento
7. Observer
8. State
9. Strategy
10. Template Method
11. Visitor

SCOPE:

1. Factory
Class 2. Adapter
3. Interpreter
4. Template Method
1. Abstract Factory
2. Builder
3. Prototype
4. Singleton
5. Adapter
6. Bridge
7. Composite
8. Decorator
9. Façade
Object 10. Flyweight
11. Proxy
12. Chain of Responsibility
13. Command
14. Iterator
15. Mediator
16. Memento
17. Observer
18. State
19. Strategy

3
Principles of design patterns:

1. Programming to an interface, not an implementation:


Class versus Interface implementation:
To understand this, it is imp. to understand the difference between a class and a type. An
object’s class defines how the object is implemented. The class defines the
object’s internal state and the implementation of its operations whereas; an
object’s type only refers to its interface- the set of requests to which it can
respond. An object can have many types, and objects of different classes can
have the same type. There is a close relationship between a class and the type.
Because a class defines the operations an object can perform, it also defines the
object’s type.
Class inheritance defines an object’s implementation in terms of another object’s
implementation. It’s a mechanism for code and representation sharing.
Interface inheritance describes when an object can be used in place of another.

Class inheritance is a mechanism for extending application functionality by reusing


functionality in parent classes. It lets us to define a new object rapidly in terms
of an old one. It lets us to get new implementations almost for free. Inheriting
what we need from existing classes. If inheritance is used properly, all classes
derived from an abstract class will share its interface. This implies that a
subclass merely overrides or adds operations and does not hide the operations
of the parent class.
There are two benefits to manipulating objects solely in terms of the interface defined by
abstract classes:
Clients remain unaware of the specific types of objects they use, as long as the objects
adhere to the interface that clients expect.
Clients remain unaware of the classes that implement these objects. Clients only know
about the abstract class defining the interface.

To implement this principle, we should not declare variables to be instances of particular


concrete classes. Instead, we should commit only to an interface by an abstract
class. Creational patterns ensure that the system is written in terms of
interfaces, not implementations.

2. Favor Object composition over class inheritance:

Inheritance versus composition:


Class inheritance lets us to define the implementation of one class in terms of another’s.
Reuse by subclassing is referred to as white-box reuse. The term “white-box”
refers to visibility: With inheritance, the internals of parent class are often
visible to subclasses.

4
Object composition is an alternative to class inheritance. In this technique, new
functionality is obtained by assembling or composing simple objects into a
more complex object or functionality. Object composition is defined
dynamically at runtime through objects acquiring references to other objects.
Any object can be replaced by any other runtime as long as it they have the
same type.

Disadvantages of inheritance:
The implementations inherited from the parent classes can’t be changed at runtime
because inheritance is defined statically at compile time.
Parent classes often define at least a part of their subclasses’ physical representation. As
inheritance exposes a subclass to details of it s parent’s implementation, its
often said that “inheritance breaks encapsulation”. If any implementation in the
parent class is changed, the subclass also has to be changed.
If any aspect of inherited implementation is not appropriate for the new domain, then the
parent class must be rewritten or replaces by something more appropriate. This
dependency limits flexibility and ultimately reusability.

Advantages of composition:
It helps to keep each class encapsulated and focused on one task.
The classes and class hierarchies will remain less and will less likely grow into
unmanageable monsters.
A design based on object composition will have more objects and the system’s behavior
will depend on their interrelationships instead of being defined in one class.
Ideally, you shouldn't have to create new components to achieve reuse. You should be
able to get all the functionality you need just by assembling existing components through
object composition. But this is rarely the case, because the set of available components is
never quite rich enough in practice. Reuse by inheritance makes it easier to make new
components that can be composed with old ones. Inheritance and object composition thus
work together.

Delegation:
Delegation is a way of making composition as powerful as delegation. In delegation, two
objects are involved in handling a request; the receiving objects that receives the request
delegates the operations to the delegate. This is analogous to subclasses deferring the
requests to the parent classes. But instead of inheritance, the receiving class will have a
reference to the delegate class and explicitly forwards the request to that reference.
The main advantage of delegation is that it makes it easy to compose behaviors at run-
time and to change the way they’re composed.
Delegation is heavily used in the State, Strategy and Visitor patterns. Mediator,
Chain of Responsibility and Bridge patterns use delegation less heavily.

3. Designing for change:


The key to maximizing reuse lies in anticipating new requirements and changes to
existing requirements, and in designing systems so that they can evolve accordingly. To

5
design a system that’s robust to such changes, it is important to consider how the system
might change over its lifetime. If a design doesn’t take into account the changes that
might occur in future, it might lead to redesign involving class redefinition and
reimplementation, client modification, and retesting.

Some common causes of redesign are:


1. Creating an object by specifying a class explicitly: Specifying a class name when you
create an object commits you to a particular implementation instead of a particular
interface. This commitment can complicate future changes. To avoid it, create objects
indirectly.
2. Dependence on specific operations: When you specify a particular operation, you
commit to one way of satisfying a request. By avoiding hard-coded requests, you make it
easier to change the way a request gets satisfied both at compile-time and at run-time.
3. Dependence on object representations or implementations: Clients that know how an
object is represented, stored, located, or implemented might need to be changed when the
object changes. Hiding this information from clients keeps changes from cascading.
4. Algorithmic dependencies: Algorithms are often extended, optimized, and replaced
during development and reuse. Objects that depend on an algorithm will have to change
when the algorithm changes. Therefore algorithms that are likely to change should be
isolated.
5. Tight coupling: Classes that are tightly coupled are hard to reuse in isolation, since
they depend on each other. Tight coupling leads to monolithic systems, where you can't
change or remove a class without understanding and changing many other classes. The
system becomes a dense mass that's hard to learn, port, and maintain. Loose coupling
increases the probability that a class can be reused by itself and that a system can be
learned, ported, modified, and extended more easily. Design patterns use techniques such
as abstract coupling and layering to promote loosely coupled systems.
6. Extending functionality by subclassing: Customizing an object by subclassing often
isn't easy. Every new class has a fixed implementation overhead (initialization,
finalization, etc.). Defining a subclass also requires an in-depth understanding of the
parent class. For example, overriding one operation might require overriding another. An
overridden operation might be required to call an inherited operation. And subclassing
can lead to an explosion of classes, because you might have to introduce many new
subclasses for even a simple extension. Object composition in general and delegation in
particular provide flexible alternatives to inheritance for combining behavior. New
functionality can be added to an application by composing existing objects in new ways
rather than by defining new subclasses of existing classes. On the other hand, heavy use
of object composition can make designs harder to understand. Many design patterns
produce designs in which you can introduce customized functionality just by defining one
subclass and composing its instances with existing ones.
7. Inability to alter classes conveniently: Sometimes you have to modify a class that
can't be modified conveniently. Perhaps you need the source code and don't have it (as
may be the case with a commercial class library). Or maybe any change would require
modifying lots of existing subclasses. Design patterns offer ways to modify classes in
such circumstances.

6
Frameworks:
A framework is a set of cooperating classes that make up a reusable design for a specific
class of software. The framework dictates the architecture of your application. It will
define the overall structure, its partitioning into classes and objects, the key
responsibilities thereof, how the classes and objects collaborate, and the thread of control.
A framework predefines these design parameters so that you, the application
designer/implementer, can concentrate on the specifics of your application. The
framework captures the design decisions that are common to its application domain.
Frameworks thus emphasize design reuse over code reuse, though a framework will
usually include concrete subclasses you can put to work immediately.
Differences between a framework and a design pattern:
1. Design patterns are more abstract than frameworks. Frameworks can be embodied in
code, but only examples of patterns can be embodied in code. A strength of frameworks
is that they can be written down in programming languages and not only studied but
executed and reused directly. In contrast, the design patterns in this book have to be
implemented each time they're used. Design patterns also explain the intent, trade-offs,
and consequences of a design.
2. Design patterns are smaller architectural elements than frameworks. A typical
framework contains several design patterns, but the reverse is never true.
3. Design patterns are less specialized than frameworks. Frameworks always have a
particular application domain. A graphical editor framework might be used in a factory
simulation, but it won't be mistaken for a simulation framework. In contrast, the design
patterns in this catalog can be used in nearly any kind of application. While more
specialized design patterns than ours are certainly possible (say, design patterns for
distributed systems or concurrent programming), even these wouldn't dictate an
application architecture like a framework would.

Design Pattern Aspect(s) That Can Vary:

Design Patterns Aspects that can vary


Abstract Factory families of product objects
Builder how a composite object gets created
Factory Method subclass of object that is instantiated
Prototype class of object that is instantiated
Singleton the sole instance of a class
Adapter interface to an object
Bridge implementation of an object
Composite structure and composition of an object
Decorator responsibilities of an object without subclassing
Facade interface to a subsystem
Flyweight storage costs of objects
Proxy how an object is accessed; its location
Chain of Responsibility object that can fulfill a request
Command when and how a request is fulfilled
Interpreter grammar and interpretation of a language

7
Iterator how an aggregate's elements are accessed, traversed
Mediator how and which objects interact with each other
Memento what private information is stored outside an object, and when
Observer number of objects that depend on another object; how the
dependent objects stay up to date
State states of an object
Strategy an algorithm
Template Method steps of an algorithm
Visitor operations that can be applied to object(s) without changing their
class(es)

Creational Patterns:
1. Singleton pattern: It is of a class where there can be no more than one instance. It
provides a single global point of access to that instance.
This is used when there is a need to make sure that there can be only one instance of a
class. The easiest way is to embed a static variable inside the class that is set on the first
instance and check for each time when the constructor is called. This is because a static
variable can have only one instance.

A way to check if only one instance is created for a class is to throw an exception when
more than one instance is created.

Another way is to create a final class like Math class which has all static members, for
which any instance cannot be created directly but can only call the static methods of the
class.

 The third way is to create a singleton pattern using static methods to create and keep
track of instances. The constructor of the class is made private to ensure that an instance
can be created only from within the static method of the class.

Consequences of a singleton:
1. It can be difficult to subclass a Singleton, since this can work only if the base has not
yet been instantiated.
2. You can easily change a singleton to allow a small number of instances where this is
allowable and meaningful.

Examples:
CASE 1:
class SingletonException extends RuntimeException
{
//new exception type for singleton classes
public SingletonException()
{
super();
}
//-----------------------------------------------

8
public SingletonException(String s)
{
super(s);
}
}

class PrintSpooler
{
//this is a prototype for a printer-spooler class
//such that only one instance can ever exist
static boolean instance_flag=false; //true if 1 instance
public PrintSpooler() throws SingletonException
{
if (instance_flag)
throw new SingletonException("Only one spooler allowed");
else
instance_flag = true; //set flag for 1 instance
System.out.println("spooler opened");
}
//-------------------------------------------
public void finalize()
{
instance_flag = false; //clear if destroyed
}
}

public class singleSpooler


{
static public void main(String argv[])
{
PrintSpooler pr1, pr2;
//open one spooler--this should always work
System.out.println("Opening one spooler");
try{
pr1 = new PrintSpooler();
}
catch (SingletonException e)
{System.out.println(e.getMessage());}
//try to open another spooler --should fail
System.out.println("Opening two spoolers");
try{
pr2 = new PrintSpooler();
}
catch (SingletonException e)
{System.out.println(e.getMessage());}
}
}
Then, if we execute this program, we get the following results:
Opening one spooler
printer opened
Opening two spoolers
Only one spooler allowed

CASE 2:
final class PrintSpooler
{
//a static class implementation of Singleton pattern
static public void print(String s)
{
System.out.println(s);

9
}
}
//==============================
public class staticPrint
{
public static void main(String argv[])
{
Printer.print("here it is");
}
}

CASE 3:
class iSpooler
{
//this is a prototype for a printer-spooler class such that only one instance
can ever exist
static boolean instance_flag = false; //true if 1 instance
//the constructor is privatized-
//but need not have any content
private iSpooler() { }
static public iSpooler Instance() {
if (! instance_flag)
{
instance_flag = true;
return new iSpooler(); //only callable from within
}
else
return null; //return no further instances
}
//-------------------------------------------
public void finalize()
{
instance_flag = false;
}
}

Factory Pattern

It deals with the problem of creating objects without specifying the exact class of object
that will be created. This pattern handles this problem by defining a separate method for
creating objects which subclasses can then override to specify the derived type of product
that will be created.
Factory pattern promotes loose coupling by eliminating the need to bind application
specific classes into the code.
Factory pattern is all about:
“Define an interface for creating an object, but let the subclasses decide which class to
instantiate. The factory method lets a class defer instantiation to subclasses.” Thus, as
defined by Gamma et al, “The Factory method lets a class defer instantiation to
subclasses.”

10
Creator

+ factory( ) : Product

ConcreteCreator
Product

+ factory( ) : Product

When to use a factory pattern:


• A class can’t anticipate which kind of class of objects it must create.
• A class uses its subclasses to specify which objects it creates.
• You want to localize the knowledge of which class gets created.

Variations of factory pattern that make it easy to recognize:


• The base class is abstract and the pattern must return a complete working class.
• The base class contains default methods and is only subclassed for cases where
the default methods are insufficient.
• Parameters are passed to the factory telling it which of several class types to
return. In this case, classes may share the same method names but nay do
something quite different.

Common Usage:

• It is common in toolkits and frameworks where library code needs to create


objects of types which may be subclassed by applications using the framework.
This is because frameworks exist at an abstract level. Usually they do not know
and should not be concerned about instantiating specific objects. They need to
defer the decisions about specific objects to the users of the framework.
• Parallel class hierarchies often require objects from one hierarchy to be able to
create appropriate objects from another.
There is a principle of object-oriented design known as the “Dependency Inversion
Principle (DIP)”. This principle tells that we should try to avoid depending on things
that are concrete. For example, given the choice between holding a reference to a List or

11
its derivative LinkedList, we should choose the base class List. In other words, rather
than writing
LinkedList balls = new LinkedList ( );
It’s better to write,
List balls = new LinkedList ( );

The DIP says: "Depend on abstractions, not on concretions” .In the Factory Method
pattern, we add abstract make methods to the class that needs to create the instances of the
objects. Then, in derivatives of that class, we implement those make methods
appropriately.

Logical Model:

There are countless variations of the Factory pattern, although most variants typically use
the same set of primary actors, a client, a factory, and a product. The client is an object
that requires an instance of another object (the product) for some purpose. Rather than
creating the product instance directly, the client delegates this responsibility to the
factory. Once invoked, the factory creates a new instance of the product. To put it simply,
the client uses the factory to create the instance of the product. The factory completely
abstracts the creation and initialization of the product from the client. This indirection
enables the client to focus on its discrete role in the application without concerning itself
with the details of how the product is created. Thus, as the product implementation
changes over time, the client remains unchanged.
The most important aspect of this pattern is that the client is abstracted both from
the type of product and the type of factory used to create the product. Presuming that the
product interface is invariant, this enables the factory to create any product type it deems
appropriate. Furthermore, presuming that the factory interface is invariant, the entire
factory along with the associated products it creates can be replaced in a wholesale
fashion. Both these radical changes occur without any change to the client.

uses creates
Client Factory Product

Factory pattern logical Model

Physical Model:

Most implementations of the factory pattern use two abstract classes, Factory and
Product to provide the invariant interfaces discussed in the logical model. The Client
uses an instance of a concrete subclass of Factory (ConcreteFactory) to create an
instance of a concrete Product subclass (ConcreteProduct). Since all the variables,
parameters and the method return values are typed to the Factory and Product abstract
classes, the Client is unaware of these subclasses.

12
Client

Factory Product

ConcreteFactory
ConcreteProduct

Factory Pattern Physical Diagram

In Java, iterator ( ) method is a factory method. This method returns the right type of
iterator for the collection being asked for it.

The Factory Method Pattern: Key Features


Intent Define an interface for creating an object, but let subclasses decide
which class to instantiate. Defer instantiation to subclasses.
Problem A class needs to instantiate a derivation of another class, but doesn't
know which one. Factory Method allows a derived class to make
this decision.
Solution A derived class makes the decision on which class to instantiate and
how to instantiate it.
Participants and Product is the interface for the type of object that the Factory
collaborators Method creates. Creator is the interface that defines the Factory
Method.
Consequences Clients will need to subclass the Creator class to make a particular
ConcreteProduct.
Implementation Use a method in the abstract class that is abstract (pure virtual in C+
+). The abstract class' code refers to this method when it needs to
instantiate a contained object but does not know which particular
object it needs.

Sample Code

Consider a simple case in which we could use a Factory class. Suppose we have an entry
form and we want to allow the user to enter his name either as "firstname lastname" or as

13
"lastname, firstname." We'll make the further simplifying assumption that we will always
be able to decide the name order by whether there is a comma between the last and first
name.

This is a pretty simple sort of decision to make, and you could make it with a simple if
statement in a single class, but let's use it here to illustrate how a factory works and what
it can produce. We'll start by defining a simple base class that takes a String and splits it
(somehow) into two names:

public class Namer {


//base class extended by two child classes
protected String last; //split name
protected String first; //stored here

public String getFirst() {


return first; //return first name
}
public String getLast() {
return last; //return last name
}
}

In this base class, we don't compute any names as such, but we do provide
implementations of the getFirst and getLast methods. We'll store the split first and
last names in the Strings first and last, and, since the subclasses will need access to these
variables, we'll make them protected.

Now we can write two very simple subclasses that split the name into two parts in the
constructor. In the FirstFirst class, we make the simplifying assumption that everything
before the last space is part of the first name.

public class FirstFirst


extends Namer {
//extracts first name from last name
//when separated by a space
public FirstFirst(String s) {
int i = s.lastIndexOf(" "); //find sep space
if (i > 0) {
first = s.substring(0, i).trim();
last = s.substring(i + 1).trim();
} else {
first = ""; // if no space
last = s; // put all in last name
}
}

14
}

And in the LastFirst class, we assume that a comma delimits the last name. In both
classes, we also provide error recovery in case the space or comma does not exist.

public class LastFirst extends Namer {


// extracts last name from first name
// when separated by a comma
public LastFirst(String s) {
int i = s.indexOf(","); //find comma
if (i > 0) {
last = s.substring(0, i).trim();
first = s.substring(i + 1).trim();
} else {
last = s; //if no comma,
first = ""; //put all in last name
}
}
}

Building the Simple Factory

Now our simple Factory class is extremely simple. We just test for the existence of a
comma and then return an instance of one class or the other.

public class NamerFactory {


//Factory decides which class to return based on
//presence of a comma
public Namer getNamer(String entry) {
//comma determines name order
int i = entry.indexOf(",");
if (i > 0)
return new LastFirst(entry);
else
return new FirstFirst(entry);
}
}

SAMPLE 2:
Implementation of Factory Pattern:

Abstract Class:

package factoryPattern;

15
public class DisplayGrantedShares {
public void displayShares(){
System.out.println("Select an appropriate type of share");
}

}
Concrete Implementations of Products:

class AwardsDisplay extends DisplayGrantedShares{


public void displayShares(){
System.out.println("Displaying Granted Awards");
}
}

class OptionsDisplay extends DisplayGrantedShares{


public void displayShares(){
System.out.println("Displaying Granted Options");
}
}

class PurchaseDisplay extends DisplayGrantedShares{


public void displayShares(){
System.out.println("Displaying Granted Purchases");
}
}

Factory Class:

package factoryPattern;

public class SharesDisplayFactory {

String shareType;
public SharesDisplayFactory(String shareType){
this.shareType=shareType;
display().displayShares();
}

public DisplayGrantedShares display(){


if(shareType.equalsIgnoreCase("Awards")){
return new AwardsDisplay();
}else if(shareType.equalsIgnoreCase("Options")){
return new OptionsDisplay();
}else if(shareType.equalsIgnoreCase("Purchases")){

16
return new PurchaseDisplay();
}else{
return new DisplayGrantedShares();
}
}

Client Class:

package factoryPattern;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class ShareDisplayClient {

public static void main(String[] args) {


String shareType=null;

System.out.println("Please Enter the Share Type to display : ");

BufferedReader br=new BufferedReader(new InputStreamReader(System.in));


try {
shareType=br.readLine();
} catch (IOException ex) {
ex.printStackTrace();
}

new SharesDisplayFactory(shareType);
}

ABSTRACT FACTORY PATTERN

Abstract factory pattern provides a way to encapsulate a group of individual factories that
have a common theme. This pattern is one level abstraction higher than factory pattern. It
is an object creational pattern. Sometimes several objects need to be instantiated in a
coordinated fashion. For example, when dealing with user interfaces, the system might
need to use one set of objects to work on one operating system and another set of objects

17
to work on a different operating system. The Abstract Factory pattern ensures that the
system always gets the correct objects for the situation.

Intent:
The intent of abstract factory pattern is to provide an interface for creating families of
related or dependent objects without specifying their concrete classes.

When to use:

• The client should be independent of how the products are created.


• The application should be configured with one of multiple families of products.
• Objects need to be created as a set, in order to be compatible.
• You want to provide a collection of classes and you want to reveal just their
contracts and their relationships, not their implementations.

Description:

For example, an application needs to use a variety of resources or operating


environments. Some common ones include:
• Windowing (An application’s GUI)
• A file system
• Communication with other applications and systems.

In this sort of application, you want to make the application flexible enough to use a
variety of these resources without having to recode the application each time a new
resource is added.
An effective way to solve this problem is to define a generic resource creator, the
Abstract factory. The factory has one or more create methods, which can be called to
produce generic resources or abstract products. Java ("Java technology") runs on many
platforms, each with many different implementations of a file system or windowing. The
solution Java has taken to abstract the concepts of files and windowing and not show the
concrete implementation. You can develop the application using the generic capabilities
of the resources as though they represented real functionality. During runtime,
ConcreteFactories and ConcreteProducts are created and used by the application. The
concrete classes conform to the contract defined by the AbstractFactory and
AbstractProducts, so the concrete classes can be directly used, without being recoded or
recompiled.

Implementation:

Abstract Factory class diagram

18
You typically use the following to implement the Abstract Factory pattern:

• AbstractFactory – An abstract class or interface that defines the create methods


for abstract products.
• AbstractProduct – An abstract class or interface describing the general behavior
of the resource that will be used by the application.
• ConcreteFactory – A class derived from the abstract factory. It implements create
methods for one or more concrete products.
• ConcreteProduct – A class derived from the abstract product, providing an
implementation for a specific resource or operating environment.

Benefits:

• An Abstract Factory helps to increase the overall flexibility of an application.


This flexibility manifests itself both during design time and runtime.
• During design, you do not have to predict all future uses for an application.
Instead, you create the generic framework and then develop implementations
independently from the rest of the application. At runtime, the application can
easily integrate new features and resources.

19
• A further benefit of this pattern is that it can simplify testing the rest of the
application. Implementing a TestConcreteFactory and TestConcreteProduct is
simple; it can simulate the expected resource behavior.

Difference between abstract factory and factory:


• The abstract factory pattern provides an interface for creating a family of objects
whereas factory method provides an interface for creating one object
• Factory is a class creational pattern and abstract factory is an object creational
pattern.
The difference lies in how dynamic the substitution needs to be. In both
cases the Product and the Factories to produce them are generalizations.
The difference is that in Factory Method the subclasses in each
generalization map 1:1 to each other while in Abstract Factory the
Factory subclasses map 1:* to Product subclasses.
Thus in Factory Method a concrete factory object can instantiate exactly
one flavor of one Product. But in Abstract Factory a single concrete
factory object can instantiate a different flavor of Product from each
of multiple Product generalizations. IOW, one uses Factory Method when
there is only one family of products and one uses Abstract Factory when
there are construction similarities across multiple families of products.

Provides an interface for creating families of related or dependent objects without


specifying their concrete classes.

Applicability

• Need to abstract from details of implementation of products


• Need to have multiple families of products
• Need to enforce families of products that must be used together
• Need to hide product implementations and just present interfaces

20
Consequences

• Isolates concrete classes


• Makes exchanging product families easy
• Promotes consistency among products
• Supporting new kinds (in each family) of products in difficult

Creational Patterns: Class and Object

The class creational pattern uses inheritance effectively in the instantiation process and
the object creational pattern uses delegation to get the job done.

Sample 1:
package abstractfactory;

public class Workstation extends Computer {

public Parts getRAM() {


return new Parts("1 GB");
}

public Parts getProcessor() {


return new Parts("Intel P 3");
}

public Parts getMonitor() {


return new Parts("19 inches");
}
}

package abstractfactory;
public class Server extends Computer{

public Parts getRAM() {


return new Parts("4 GB");
}

public Parts getProcessor() {


return new Parts("Intel P 4");
}

public Parts getMonitor() {


return new Parts("17 inches");
}
}

public class PC extends Computer {

public Parts getRAM() {


return new Parts("512 MB");
}

21
public Parts getProcessor() {
return new Parts("Celeron");
}

public Parts getMonitor() {


return new Parts("15 inches");
}
}

public abstract class Computer {

public abstract Parts getRAM();

public abstract Parts getProcessor();

public abstract Parts getMonitor();

}
public class ComputerType {
private Computer comp;

public static void main(String[] args) {

ComputerType type = new ComputerType();

Computer computer = type.getComputer("PC");

System.out.println("Monitor:
"+computer.getMonitor().getSpecification());
System.out.println("RAM:
"+computer.getRAM().getSpecification());
System.out.println("Processor:
"+computer.getProcessor().getSpecification());
}

public Computer getComputer(String computerType) {


if (computerType.equals("PC"))
comp = new PC();
else if(computerType.equals("Workstation"))
comp = new Workstation();
else if(computerType.equals("Server"))
comp = new Server();
return comp;
}
}
public class ComputerType {
private Computer comp;

public static void main(String[] args) {

ComputerType type = new ComputerType();

Computer computer = type.getComputer("PC");

22
System.out.println("Monitor:
"+computer.getMonitor().getSpecification());
System.out.println("RAM:
"+computer.getRAM().getSpecification());
System.out.println("Processor:
"+computer.getProcessor().getSpecification());
}

public Computer getComputer(String computerType) {


if (computerType.equals("PC"))
comp = new PC();
else if(computerType.equals("Workstation"))
comp = new Workstation();
else if(computerType.equals("Server"))
comp = new Server();
return comp;
}
}

Prototype Pattern

Intent:
"Specify the kinds of objects to create using a prototypical instance, and create new
objects by copying this prototype.”

Intent seen through real life:


The prototype pattern suggests that when you have a requirement for a product class,
instead of trying to create the object from scratch, you pick the best candidate from a set
of possible matches and you tweak the object to fit the exact characteristics required. So,
the idea behind the prototype pattern is to create a new object by starting with one of
several basic designs which have most of the features which you currently need to be in
the new object. The client will then tweak the object which is returned so that it looks and
behaves exactly in the manner that is required for the current situation.

In the prototype pattern, we have several prototype-classes which are classes with basic
features that we may want-already built in. Each prototype is a point-of-departure for
coming up with the specific design which we require. But using one of the prototypes
saves us from having to construct the product from scratch. We just make a few changes
here and there and we have met the requirements.

Sitting between the client and the prototypes are the prototype-manager and the Abstract-
Prototype. The prototype manager is just a class which holds a reference to the
Prototypes which are available for use by the client, (much like a catalogue has a set of
pictures of products the mail-order shopper can order). The client will forward requests to
the prototype manager to return one of the prototypes it "knows" about. There is usually a
bit of logic which the Prototype manager performs to figure out which Prototype to
return, but that's the basic job of the prototype manager.

Now here's the trick with the Prototype pattern. The Abstract-Prototype. This class
governs the behaviour of the Prototypes and ensures that they implement a method for

23
copying or "cloning" themselves along with the functionality that the client is actually
interested in. If you are going to make a lot of changes to the prototype after you get
access to it, and the same prototype may be needed-untouched-by another client later on,
then you have to ensure that the first client gets a true copy of the prototype and not just
an object reference to the same prototype.

Intent seen through the O/S and applications:


If you look at the new document dialog box in Word or Excel, you will see the prototype
pattern in principle. When creating a Fax Letter head, you wouldn't want to start from
scratch. Instead you will select from one of the templates provided with Word.. The user
simply customizes the basic document to make it fit the exact purpose intended, by filling
in the addressee's name, phone number, the date and so on.

In this case, the concrete-prototypes are the individual FAX templates, the Prototype
manager is the Templates Dialog box, the client is your new Word FAX cover page and
the abstract-prototype is the requirements which all Fax-Templates must meet
(specification for headings etc)

Motivation:

24
Problem:
The GraphicTool class belongs to the framework, while the graphical classes are
application-specific, so the GraphicTool class doesn't know how to create graphical
objects and then operate on them.

Solution:
Method 1:

This method will produce many subclasses that are different only in the kind of music
objects they instantiate.

Method 2: (Prototype Pattern)

25
To create a new graphical object, the prototypical instance of the specific graphical class
is passed as parameter to the constructor of the GraphicTool class. The GraphicTool class
can then use this prototype to clone a new object and operate on it.
Therefore, if all the Graphic subclasses support a Clone operation, then the GraphicTool
Class can clone any kind of Graphic.

Prototype Pattern can also be used to reduce the number of classes. E.G. the WholeNote
and HalfNote class only differ in that they have different bitmaps and durations. Instead
of defining a subclass of MusicalNote class for each type of notes, we can make the
MusicalNote class concrete, and the note objects can be instances of the same
MuscialNote class initialized with different setting. Therefore, for GraphiTool class, to
create a new WholeNote object is to clone a prototype that is MuscialNote object
initialized to be a WholeNote.

A
pplicability
Use Prototype Pattern when a system should be independent of how its products are
created, composed, and represented, and

1. When the classes to instantiate are specified at run-time; or for example, the dynamic
loaded class won't be specified until it is loaded, the instance of this kind of classes could
only be created at run-time.

26
2. To avoid building a class hierarchy of factories that parallels the class hierarchy of
products; or In Abstract Factory Pattern, we need to build concrete factory subclass for
each product family even if they differ only slightly. Using Prototype Pattern, We only
need one concrete factory. The concrete factory is parameterized with the prototypical
instance of each product in the family. The concrete factory then uses these prototypes to
create new objects.

3. When instances of a class can have one of only a few different combinations of state.
E.G. instances of MusicalNotes class can be either WholeNote object or HalfNote object.
Instead of using new MusicalNote with approriate state information each time to create a
new WholeNote (HalfNote) object, we can clone a WholeNote (HalfNote) prototype to
create a new WholeNote (HalfNote) object.

Structure

Participants

• Prototype: declares an interface for cloning itself.


• ConcretePrototype: implements the operation for cloning itself.
• Client: creates a new object by asking a prototype to clone itself.

27
Collaborations

• A client asks a prototype to clone itself.

Consequences
1 .Isolating concrete product classes from the client.
Because the prototype encapsulates the responsibility and the process of creating objects,
it isolate clients from implementation class.

2. Dynamically adding and removing products at run-time:


By using prototype manager, client can install and remove prototypes of new concrete
product classes at run-time. The prototype manager would be explained in details in the
implementation section.
3. Specifying new objects by varying values:
New objects can be created by simply changing the value of the prototype reference.
4. Specifying new objects by varying structure:
If the components of the composite object and composite object itself support prototype,
changing the prototypical components would change the structure of the composite
object, and therefore composite object is changed.
5. Reducing the need for subclassing:
A moment ago, we talked about reducing concrete factory subclassing in Abstract
Factory Pattern, or reducing slightly different subclass into a same class by using
Prototype Pattern. Prototype Pattern can also be used to replace Factory Method Pattern
to create new objects. Hence, the class hierarchy in Factory Method Pattern can be given
up.
6. Configuring an application with classes dynamically:
For dynamically loaded classes, we can only create instances of such classes at run-time.
If the run-time environment creates an instance of each class automatically when it's
loaded, and it registers the instance with a prototype manager. Then the application can
ask the prototype manager for prototypical instances of newly loaded classes, and clone
the prototypes to create new objects of newly loaded classes.
7. Main liability:
Each subclass of Prototype should implement the Clone operation. It's difficult to add
Clone to existing classes. Furthermore, implementing clone can be difficult if the internal
components of the prototype object don't support copying or have circular references.

Implementation

1. Using a prototype manager:


When the number of prototypes in a system can be created and destroyed dynamically, a
registry of available prototypes should be kept. The registry is called prototype manager.
The prototype manager is responsible for managing the registered prototypes. The
managing operations could be: register a prototype under a key, retrieve a prototype with
a given key, unregister a registered prototype, and etc. The clients can use the interface of
prototype manager to store and retrieve prototypes from the registry at run-time.
Normally, a client will ask the prototype manager for a prototype before cloning it.

28
2. Implementing the Clone operation.
Deep clone vs. Shallow clone:
A deep clone will clone the instance variables in the cloning object while a shallow clone
share the instance variables between the clone and the original.
A shallow clone is simple and often sufficient. But cloning prototypes with complex
structures usually requires deep clone so that the clone and the original are independent.
For a successful deep clone, the components of the clone should be the clones of the
prototype's components (i.e. the prototype's components should be clonable).

Circular References:
It's difficult to implement clone if the cloning prototype contains circular references.

3. Initializing clones.
Sometimes, the clone should be initialized by its internal states after it is created. These
values can not be passed to the Clone operation; otherwise the uniform Cloning interface
of the Clone operation would be destroyed. The initialization can be done either by using
the setting or resetting operations that already existed in the prototype classes or by
Initialize operation that takes initialization parameters as arguments and sets and the
clone's internal state accordingly.

Known Uses
• ThingLab, users could form a composite object and then promote it to a prototype by
installing it in a library of reusable objects.
• Etgdb, a debugger front-end based on ET++ that provides a point-and-click interface
to different line-oriented debuggers. It looks for a prototype with a specified name in
a global table, and then clones the prototype.
• The "interaction technique library" in Mode Composer stores prototypes of objects
that support various interaction techniques.
• The music editor example mentioned in motivation section is based on the Unidraws
drawing framework.

Sample:
There are various rhythms called taxi, BackYard and Pepper seed. A studio engineer will
voice one of them.

29
UML diagram:

Participants:

Abstract Prototype- HotRhythm and ensures that the Concrete-Prototypes implement the
ICloneable Interface. Also ensures that they have a play method. Since it is an interacting
interface, concrete-products are returned wrapped up in it so as to be unconcerned with
the actual concrete-product at work.

Concrete Prototype - BackYard,PepperSeed, Taxi these are the products which the client
are interested in, which will be used in it operations. Implements the Abstract-Prototype
and hence are able to clone themselves and do the useful work which the client requires.

PrototypeManager - RhythmProtoTypeManager In charge of all Prototypes in the


system. Keeps a reference to the available prototypes and implements logic that decides
which prototype to clone and return when requested by the client.

Client – StudioEngineer Makes use of the Prototypes. Instantiates Prototype manager and
invokes the factory method on the Prototype manager. This factory method returns the
Prototype which matches the parameter passed to the method.

SAMPLE CODE:

Sample 1:

Abstract Prototype:

public abstract class HotRhytm implements Cloneable{

protected int drumLevel;

protected int bassLevel;

protected int guitarLevel;

30
protected String bassLine;

protected String drumTrack;

protected String guitarTrack;

protected Object clone() throws CloneNotSupportedException {

return super.clone();

public int getBassLevel() {

return bassLevel;

public void setBassLevel(int bassLevel) {

this.bassLevel = bassLevel;

public String getBassLine() {

return bassLine;

public void setBassLine(String bassLine) {

this.bassLine = bassLine;

31
public int getDrumLevel() {

return drumLevel;

public void setDrumLevel(int drumLevel) {

this.drumLevel = drumLevel;

public String getDrumTrack() {

return drumTrack;

public void setDrumTrack(String drumTrack) {

this.drumTrack = drumTrack;

public int getGuitarLevel() {

return guitarLevel;

public void setGuitarLevel(int guitarLevel) {

this.guitarLevel = guitarLevel;

32
}

public String getGuitarTrack() {

return guitarTrack;

public void setGuitarTrack(String guitarTrack) {

this.guitarTrack = guitarTrack;

Concrete Prototypes:

PEPPERSEED:

public class PepperSeed extends HotRhytm {

public PepperSeed() {

drumLevel = 5;

bassLevel = 7;

guitarLevel = 4;

bassLine = "Dooo, Doo, dup";

drumTrack = "Dumm, Dumm, Dup, Pish";

guitarTrack = "Ding, Di, Ding, Ding";

33
TAXI:

public class Taxi extends HotRhytm {

public Taxi() {

drumLevel = 6;

bassLevel = 9;

guitarLevel = 4;

bassLine = "Dum, di, Dum, Di, Dumm";

drumTrack = "Dup, Dup, Tick, Dup";

guitarTrack = "Dig, i Dig, Ding, ding";

BACKAYARD:

public class BackYard extends HotRhytm {

public BackYard() {

drumLevel = 7;

bassLevel = 8;

guitarLevel = 7;

bassLine = "Doo, Dumm, ddooo";

drumTrack = "Dup, Dup, Tick, Dup";

guitarTrack = "Di, Di, Di, Ding";

34
}

PROTOTYPE MANAGER:

import java.util.Hashtable;

public class RhythmPrototypeManager {

Hashtable rhythmTape = new Hashtable();

BackYard backYardRhythm= new BackYard();

Taxi taxiRhythm= new Taxi();

PepperSeed pepperSeedRhythm= new PepperSeed();

HotRhytm rhythmToMix;

HotRhytm selectedRhythm;

HotRhytm mixRhythmType(String rhythmName){

try {

if(rhythmName.equals("BackYard")){

rhythmTape.put(backYardRhythm,backYardRhythm.clone());

selectedRhythm=
(HotRhytm)rhythmTape.get(backYardRhythm);

else if(rhythmName.equals("Taxi")){

rhythmTape.put(taxiRhythm,taxiRhythm.clone());

selectedRhythm=
(HotRhytm)rhythmTape.get(taxiRhythm);

else if(rhythmName.equals("PepperSeed")){

35
rhythmTape.put(pepperSeedRhythm,
pepperSeedRhythm.clone());

selectedRhythm=
(HotRhytm)rhythmTape.get(pepperSeedRhythm);

rhythmToMix=(HotRhytm)selectedRhythm.clone();

} catch (CloneNotSupportedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

return rhythmToMix;

CLIENT:

public class StudioManager {

public static void main(String[] args) {

RhythmPrototypeManager rhythmSelections= new


RhythmPrototypeManager();

HotRhytm rhythmType= rhythmSelections.mixRhythmType("Taxi");

System.out.println("The features of the music voiced are");

System.out.println("Bass level: "+rhythmType.getBassLevel());

System.out.println("Guitarlevel: "+rhythmType.getGuitarLevel());

System.out.println("Drum Level: "+rhythmType.getDrumLevel());

System.out.println("BassLine: "+rhythmType.getBassLine());

System.out.println("Guitar Track: "+rhythmType.getGuitarTrack());

36
System.out.println("Drum Track: "+rhythmType.getDrumTrack());

OUTPUT:

The features of the music voiced are


Bass level: 9
Guitarlevel: 4
Drum Level: 6
BassLine: Dum, di, Dum, Di, Dumm
Guitar Track: Dig, i Dig, Ding, ding
Drum Track: Dup, Dup, Tick, Dup
Sample 2:

package com.apwebco.patterns.gof.prototype;

public abstract class Product implements Cloneable {


private String SKU;
private String description;

public Object clone() {


Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
public String getDescription() {
return description;
}
public String getSKU() {
return SKU;
}
public void setDescription(String string) {
description = string;
}
public void setSKU(String string) {
SKU = string;
}
}
public class Book extends Product {

37
private int numberOfPages;

public int getNumberOfPages() {


return numberOfPages;
}
public void setNumberOfPages(int i) {
numberOfPages = i;
}
}
public class DVD extends Product {
private int duration;

public int getDuration() {


return duration;
}
public void setDuration(int i) {
duration = i;
}
}
import java.util.*;
public class ProductCache {
private static Hashtable productMap = new Hashtable();

public static Product getProduct(String productCode) {


Product cachedProduct = (Product) productMap.get(productCode);
return (Product) cachedProduct.clone();
}

public static void loadCache() {


// for each product run expensive query and instantiate product
// productMap.put(productKey, product);
// for exemplification, we add only two products
Book b1 = new Book();
b1.setDescription("Oliver Twist");
b1.setSKU("B1");
b1.setNumberOfPages(100);
productMap.put(b1.getSKU(), b1);
DVD d1 = new DVD();
d1.setDescription("Superman");
d1.setSKU("D1");
d1.setDuration(180);
productMap.put(d1.getSKU(), d1);
}
}
public class Application {
public static void main(String[] args) {

38
ProductCache.loadCache();

Book clonedBook = (Book) ProductCache.getProduct("B1");


System.out.println("SKU = " + clonedBook.getSKU());
System.out.println("SKU = " + clonedBook.getDescription());
System.out.println("SKU = " + clonedBook.getNumberOfPages());

DVD clonedDVD = (DVD) ProductCache.getProduct("D1");


System.out.println("SKU = " + clonedDVD.getSKU());
System.out.println("SKU = " + clonedDVD.getDescription());
System.out.println("SKU = " + clonedDVD.getDuration());
}
}

Variations in prototype:

1a. Personal-Prototype Only one client references the prototype each time the program
runs, but changes it. In this case deep copying is a waste since changes to the prototype
do not affect other clients.

1b. NewsMedia-Prototype The prototype is never modified but several clients may
reference it. If this is guaranteed to be the case, then you should probably make the
properties read-only. This ensures that there is no "rogue-state object" to violate the
agreements set down by the community.

1c. Environmental-Prototype The prototype is accessed and modified by several clients,


each client is interested in the changes made by other clients. The prototype should
clearly be read/write but deep copying should not be done. Since the prototype is
automatically implemented as a singleton, returning a shallow copy ensures that changes
made by one client are seen by subsequent clients. In this particular instance deep
copying is actually dangerous since it would allow several instances to exist which may
or may not have the latest changes. This is equivalent to losing uncommitted changes in
a database because someone else read the same record you have in memory, but made
and saved changes which were committed after you committed your changes. Of course
modern databases are not susceptible to snafus such as this, but you get the picture.

1d. Evolution-Prototype Changes made to the prototype should be persisted so that


future program executions use the updates. In order to persist the changes so future
program executions do not start building the concrete-prototypes from scratch and
overhauling the prototype each time, you will need to persist the object state by saving
the state to a database or XML. Each time the program runs and instantiates a Prototype,
it does so by reading back the most current data from the database or XML file. The
builder pattern would possibly be useful in helping to re-create prototype each time
before its actual use.

39
Builder Pattern

Intent:
“Separate the construction of a complex object from its representation so that the same
construction process can create different representations.”

Intent seen through real life:

Let's say you are baking a cake from a cake mix. The basic steps which are involved in
creating a cake from the cake mix are more or less fixed. You have the possibility of
swapping several components based on availability, cost or health reasons. At the end
you are still baking a cake so the representation of the product which results changes, but
the baking (construction) process is relatively stable.
So the "cake mix baking process" is a fairly adaptable process which can be suited to a
variety of types of cakes and in this respect it reflects the builder pattern.

The idea behind the builder pattern is to create a complex or multipart object on behalf of
a client who knows what object is being created but does not know how it is being put
together. It is applicable when an object cannot be created in an arbitrary manner. It helps
the construction process to meet these requirements:
• There are several steps used to create the parts which make up the complex
object.
• These steps need to be carried out in a particular sequence.
• The product instantiation process must be hidden from the client.

The pattern advocates the association of one instantiator-class for each of the
representations of the product which may be created. All the steps for creating the
product class are written into the instantiator-class which is responsible for creating it.

Lets look at the other two issues in a bit depth:

Firstly we need to ensure that all the steps in the product instantiation sequence are
carried out. In the real life example we can use butter and flour or we can use grease
paper to line our pan, but if we skip this step we end up with a cake which cannot be
removed from the tin. We can use an electric mixer or hand mixer to mix our ingredients
but if we skip the mixing we end up with a cake which is very inconsistent: soppy in
some parts and dry in others. If we don't add eggs or some similar moistening agent, then
our cake doesn't pass the fork test. So the steps themselves are important and we can
substitute components (egg for milk) and we can substitute methods (electric mixer for
Hand mixer) but we cannot skip any step.
Secondly, we need to ensure that the steps are carried out in a particular order. If we mix
the ingredients before adding water, the mixing will not be as effective. If we put the cake
in the oven for 45 minutes, take it out and then set the temperature to 350 degrees, we end

40
up with an unbaked cake and . So the order of the steps is also important.

So we must follow all steps and in the required order. The builder pattern allows us to
ensure that the two criteria are achieved while allowing us the flexibility to substitute
methods and ingredients which suit our particular cake being baked. It achieves this by
imposing a recipe approach to composing the complex object. It does this in two parts.

Components of the builder approach:


1. AbstractBuilder: It is represented by the general cake baker who knows all the steps
which are needed for composing the complex object. Because all our specialist cake
bakers are familiar with the steps needed for cake baking, it ensures that there is expertise
in all the steps to be executed. The GeneralCakeBaker interviews all specialist bakers
before they can be employed in the bakery. She ensures that the SpecialistCakeBaker is
expert in all the steps which are specific to the kind of cake they are supposed to be
baking. Later you will understand why, but for now, accept that the specialist bakers must
know all the steps in bold-italic[/italic] (they are abstract steps) but not necessarily the
steps in bold (they are concrete steps), since she already knows those general steps. Note
also that some of the steps are already filled in. Also, in our cake baking example, the
order is not important. In fact it is an unordered list, looking something like:
GeneralCakeBaker (AbstractBuilder)
• Add_MoisteningAgent:[/italic]
• Bake contents: Pour contents into tin. Set timer for 45 minutes, place tin in oven
and remove when timer sounds. Turn off oven.
• Mix till consistent:[/italic]
• Grease pan:[/italic]
• Set oven temperature: Turn knob to 375 degrees
• Pour in CakeMix:[/italic]

2. ConcreteBuilder: Each type of product (cake) which can be created is tied to one
specialist baker. He knows how to carry out each of the steps in the general recipe for the
particular type of cake he bakes and so we can consider him to be an extension of the
GeneralCakeBaker. However each baker can bake only the type of cake which he
specializes in. So we may have the ChocolateCakeBaker, OrangeCakeBaker,
FruitCakeBaker etc. Only the ChocolateCakeBaker can make ChocolateCake and the
OrangeCakeBaker must know how to carry out all the steps which apply to the baking of
an Orange cake. In reality he only needs to know the steps which are indicated in bold-
italics[/italic]. The other steps which are in bold are considered general steps, do not need
specialization and so will be taken care of by the GeneralCakeBaker herself. The
specialist cake baker can override the Master baker however and so the Chocolate cake
baker can bake his cake for less time at a higher temperature if so desired. Since
knowledge of the steps must reflect all the steps as outlined by the GeneralCakeBaker, it
ensures that the SpecialistCakeBaker is in a position to do all the steps. The great thing
though is that we can customize the cake we make by changing the SpecialistCakeBaker
we use to bake it. Because all specialists know the steps relevant to their cake, it ensures
our cake is baked completely. Each specific cake baker in our example reflects the role of

41
the concrete-builder in the Builder pattern. Note very importantly, that in our
example, the specialist cake bakers do not know the order in which the steps are
carried out. As we will see, the MasterCakeBaker knows the order of the steps and
will take care of the sequencing requirement.

3. Director: The Director in the pattern is represented by our MasterCakeBaker. The


director ensures that the steps are executed in the right order. In our case the director, an
experienced baker, knows the order in which the steps must be executed in order to
ensure that the cake is baked properly and orders the specialist cake baker to carry out
each step in turn. So he may call the specialistCakeBaker and tell him to get going, then
call out the following instructions which the specialist must execute in the following
order. (ITSB stands for - Instruction To Specialist Baker).
a. ITSB: "Grease pan"
b. ITSB: "Set oven temperature"
c. ITSB: "Pour in CakeMix"
d. ITSB: "Add_MoisteningAgent"
e. ITSB: "Mix till consistent"
f. ITSB: "Bake contents

Note something very important here though. The MasterCakeBaker has a communication
problem and only gets along with people he has known for a long time. Worse yet, the
specialist cake bakers and premadonnas and are themselves difficult to get along with. So
we shield the MasterCakeBaker from the flightiness of the SpecialistCakeBakers and he
only deals with the GeneralCakeBaker who has been around since the bakery started. So
in reality, he speaks to the SpecialistCakeBaker through the GeneralCakeBaker. He never
knows the specialistCakeBaker on duty and doesn't care. Now the GeneralCakerBaker
implements the step that she can, but passes on the specialized steps to the Specialist. In
so doing, we get our cake baked, but without any direct contact between the
MasterCakeBaker (Director) and SpecialistCakeBakers (Abstract Builder). This is
just as well because they are easily offended and the fact that the MasterCakeBaker
cannot remember their names is very offensive to each of them.

4. ConcreteProduct: The complex object in our example is the cake and it reflects the
role of the concrete product in the builder pattern. Remember each concrete product is
built by only one builder. In fact selecting the builder is in effect, selecting the product.
So when we select the OrangeCakeBaker, we are guaranteed to get back an Orange cake.

5. Client: The client in the pattern is similar to the customer of the bakery. In the case of
the customer, an order for a particular type of cake (or concrete product) is made. The
customer hopes that the cake will taste a bit better than concrete and that biting into it
will not require a trip to the dentist. But the other similarities are true. The only difference
is that the client in the pattern knows all about the available products and knows which
concrete-builder is responsible for each product. In fact the customers come here because
they know that the bakery has been on a drive to get all the best specialist bakers in one
place and the customers even know the names of the specialistBakers who work for the
bakery and the type of specialty cake that they bake.

42
Let's put it all together. In the bakery, the customer walks in and asks the
GeneralCakeBaker to call Oraine the OrangeCakeBaker to bake her a cake. She has heard
about the fantastic cake he bakes. The GeneralCakeBaker walks into the
MasterCakeBakers office and say "Boss, we have an order". The MasterCakeBaker
washes his hands and starts to shout instructions to the GeneralCakeBaker. The
GeneralCakeBaker knows how to do the general steps and takes care of them, but the
other steps she delegates to the SpecialistCakeBaker. The MasterCakeBaker puts the
icing on the cake and grabs credit for baking (how do you think he got to be
MasterBaker) by returning the cake to the client, who thanks him very much.

The client-code knows which concrete-product it requires at any point in time. It also
knows which concrete-builder is able to return that concrete-product. It therefore
instantiates the required concrete-builder posing as the abstract-builder. The concrete
builder has a reference to a concrete product which is automatically instantiated as well.
The client code also instantiates the director with a reference to the concrete-builder
(wrapped in the abstract-builder's interacting-interface) which it needs to make a
particular product. The client then calls the construct method on the director which in
turn invokes the methods of the concrete-builder (which it aggregates), in the sequence
required. The Director finally returns the concrete-product to the client.

UML Diagram:

Some advantages of using the builder pattern are as follow:

43
• The object oriented requirement of encapsulation is used to hide the creation of
complex objects behind an interface.
• The characterizing features of an object can be changed without changing the
manner in which the object is created.

Two disadvantages of the builder pattern are

• By using multiple classes and many methods this process of creation may create
additional overhead compared to an instance by instance creation method.
• More initial programming work to separate code to work under this approach.

Example:
Prepare a Pizza of the customer’s choice by changing the dough, topping and sauce for
each pizza.

AbstractBuilder: PizzaBuilder.java
public abstract class PizzaBuilder {
Pizza pizza = new Pizza();
public Pizza getPizza(){
return pizza;
}
public static PizzaBuilder getBuilder(PizzaBuilder pizzaBuilder){
return pizzaBuilder;
}
public void buildDough(){
pizza.setDough("Pizza Base");
}
public abstract void buildSauce();
public abstract void buildTopping();
}

Concrete Builders:

HawaainPizzaBuilder.java
public class HawaainPizzaBuilder extends PizzaBuilder {
public void buildSauce() {
pizza.setSauce("mild");
}

public void buildTopping() {


pizza.setTopping("pineapple + ham");
}
}

44
SpicyPizzaBuilder.java:
public class SpicyPizzaBuilder extends PizzaBuilder {
public void buildSauce() {
pizza.setSauce("chilly");

public void buildTopping() {


pizza.setTopping("pepper+salami");

}
}

Product: Pizza.java
public class Pizza {
private String dough="";
private String sauce="";
private String topping="";
public void setDough(String dough) {
this.dough = dough;
}
public void setSauce(String sauce) {
this.sauce = sauce;
}
public void setTopping(String topping) {
this.topping = topping;
}
public String getDough() {
return dough;
}
public String getSauce() {
return sauce;
}
public String getTopping() {
return topping;
}

45
Director: Waiter.java
public class Waiter {

private PizzaBuilder pizzaBuilder;

public Pizza constructPizza(String pizzaBuilderName, PizzaBuilder


pizzaBuilderType)
{
pizzaBuilder=PizzaBuilder.getBuilder(pizzaBuilderType);
pizzaBuilder.buildDough();
pizzaBuilder.buildSauce();
pizzaBuilder.buildTopping();
return pizzaBuilder.getPizza();
}

Client :Customer.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Customer {


public static void main(String[] args) {
Waiter waiter = new Waiter();
PizzaBuilder pizzaBuilder=null;
System.out.println("Enter the choice of pizza : HawaainPizza or
SpicyPizza ");
System.out.println("(Enter the choice as displayed here)");
String product="";
BufferedReader br = new BufferedReader( new
InputStreamReader(System.in));
try {
product=br.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(product.equalsIgnoreCase("HawaainPizza")){
pizzaBuilder=new HawaainPizzaBuilder();
}
else{

46
pizzaBuilder= new SpicyPizzaBuilder();
}
Pizza pizza=waiter.constructPizza(product,pizzaBuilder);
System.out.println("Your pizza is made of: "+ pizza.getDough()
+" ,"+pizza.getSauce()+" sauce and "+pizza.getTopping()+" topping");
}
}

47
Behavioral Patterns

Introduction:
Behavioral patterns are concerned with algorithms and the assignment of responsibilities
between objects. They describe not just the patterns of objects or classes but also the
pattern of communication between them. They characterize complex control flow that’s
difficult to follow at run time.
Behavioral class patterns use inheritance to distribute behavior between classes.
There are two such patterns: Template pattern and the Interpreter pattern. Behavioral
object patterns use object composition rather than inheritance. Some of these patterns
describe how a group of peer objects cooperate with each other to perform a task that
cannot be performed by a single object. The others are concerned with encapsulating the
behavior in an object and delegating requests to it.

1. CHAIN OF RESPONSIBILITY PATTERN:

Chain of responsibility allows decoupling between objects by passing a request from one
object to the next in a chain until the request is recognized. It lets us to send the requests
to an object implicitly through a chain of objects. Any candidate may fulfill the request
depending upon the run-time conditions. The number of candidates is open-ended, and
thus we can select which candidates participate in the chain at run-time.
It consists of a source of command objects and a series of processing objects.
Each processing object contains a set of logic that describes the types of command
objects it can handle, and how to pass off those that it cannot handle to the next
processing object.

Intent:
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 the request along the
chain until an object handles it.

Motivation:
Consider a context-sensitive help facility for a graphical user interface. The user can
obtain help information on any part of the interface just by clicking on it. The help that's
provided depends on the part of the interface that's selected and its context; for example,
a button widget in a dialog box might have different help information than a similar
button in the main window. If no specific help information exists for that part of the
interface, then the help system should display a more general help message about the
immediate context—the dialog box as a whole, for example.
Hence it's natural to organize help information according to its generality—from the most
specific to the most general. Further more, it's clear that a help request is handled by one
of several user interface objects; which one depends on the context and how specific the
available help is. The problem here is that the object that ultimately provides the help isn't
known explicitly to the object (e.g., the button) that initiates the help request. What we

48
need is a way to decouple the button that initiates the help request from the objects that
might provide help information. The Chain of Responsibility pattern defines show that
happens. The idea of this pattern is to decouple senders and receivers by giving multiple
objects a chance to handle a request. The request gets passed along a chain of objects
until one of them handles it. The first object in the chain receives the request and either
handles it or forwards it to the next candidate on the chain, which does like wise. The
object that made the request has no explicit knowledge of who will handle it—we say the
request has an implicit receiver.

Let's assume the user clicks for help on a button widget marked "Print." The button is
contained in an instance of PrintDialog, which knows the application object it belongs to
(see preceding object diagram).The following interaction diagram illustrates how the help
request gets forwarded along the chain:

In this case, neither aPrintButton nor aPrintDialog handles the request; it stops at an
Application, which can handle it or ignore it. The client that issued the request has no
direct reference to the object that ultimately fulfills it. To forward the request along the
chain, and to ensure receivers remain implicit, each object on the chain shares a common
interface for handling requests and for accessing its successor on the chain. For example,
the help system might define a HelpHandler class with a corresponding HandleHelp
operation. HelpHandler can be the parent class for candidate object classes, or it can be
defined as a mixin class. Then classes that want to handle help requests can make
HelpHandler a parent: The Button, Dialog, and Application classes use HelpHandler
operations to handle help requests. HelpHandler's HandleHelp operation forwards the
request to the successor by default. Subclasses can override this operation to provide help

49
under the right circumstances; otherwise they can use the default implementation to
forward the request.

Applicability:
The chain of responsibility pattern can be used when
• More than one object may handle a request, and the handler is not known .The
handler should be ascertained automatically.
• A request has to be issued to one of the several objects without specifying the
receiver explicitly.
• The set of objects can handle a request should be specified dynamically.

Structure:

50
A typical object structure might look like this:

Participants:
1. Handler: (HelpHandler)
• It defines an interface for handling the requests.
• It might implement the successor link.

2. ConcreteHandler: (PrintButton, PrintDialog)


• Handles the request it is responsible for.
• Can access its successor
• If it can handle the request, it does so. Otherwise it forwards the request to its
successor.

3. Client:
• Initiates the request to a ConcreteHandler object on the chain.

Collaborations:
When a client issues a request, the request propagates along the chain until a
ConcreteHandler object takes the responsibility for handling it.

Consequences:
1. Reduced coupling:
The pattern frees an object from knowing which other object handles the request. An
object has to know only that a request will be handled appropriately. The receiver and
sender do not have an explicit knowledge about each other. An object in the chain need
not know the structure of the chain. Instead of maintaining references to all the
candidates, the objects maintain only a single reference to their successor.
2. Added flexibility in assigning responsibilities to objects:
New responsibilities can be added or the existing responsibility for handling a request can
be changed by adding a handler to the chain or changing the chain at run time.
Subclassing can also be combined to specialize handlers statically.
3. Receipt is not guaranteed:
Since a request has no explicit receiver, there is no guarantee that it will be handled. The
request can fall off the end of the chain without ever being handled. A request can also go
unhandled if the chain is not configured properly.

Implementation:
1. Implementing the successor chain.
There are two possible ways to implement the successor chain:
a. Define new links (usually in the Handler, but ConcreteHandler should define them
instead).

51
b. Use existing links.
Our examples so far define new links, but often you can use existing object references to
form the successor chain. For example, parent references in a part-whole hierarchy can
define a part's successor. A widget structure might already have such links. Using
existing links works well when the links support the chain you need. It saves you from
defining links explicitly, and it saves space. But if the structure doesn't reflect the chain
of responsibility your application requires, then you'll have to define redundant links.
2. Connecting successors.
If there are no preexisting references for defining a chain, then you'll have to introduce
them yourself. In that case, the Handler not only defines the interface for the requests but
usually maintains the successor as well. That lets the handler provide a default
implementation of HandleRequest that forwards the request to the successor (if any). If a
ConcreteHandler subclass isn't interested in the request, it doesn't have to override the
forwarding operation, since its default implementation forwards unconditionally.
3. Representing requests.
Different options are available for representing requests. In the simplest form, the request
is a hard-coded operation invocation, as in the case of HandleHelp. This is convenient
and safe, but you can forward only the fixed set of requests that the Handler class defines.
An alternative is to use a single handler function that takes a request code (e.g., an integer
constant or a string) as parameter. This supports an open-ended set of requests. The only
requirement is that the sender and receiver agree on how the request should been coded.
This approach is more flexible, but it requires conditional statements for dispatching the
request based on its code. Moreover, there's no type-safe way to pass parameters, so they
must be packed and unpacked manually. Obviously this is less safe than invoking an
operation directly. To address the parameter-passing problem, we can use separate
request objects that bundle request parameters. A Request class can represent requests
explicitly, and new kinds of requests can be defined by subclassing. Subclasses can
define different parameters. Handlers must know the kind of request (that is, which
Request subclass they're using) to access these parameters. To identify the request,
Request can define an access or function that returns an identifier for the class.
Alternatively, the receiver can use run-time type information if the implementation
languages support it.

Sample Code:

The chain is:


MailHandler  FanHandler  ComplaintHandler  NewLocHandler 
SpamHandler

Handler interface:
Handler.java:
public interface Handler {
public void handleRequest(String s);

52
Concrete Handlers:
Chain Instantiator:MailHandler.java

public class MailHandler implements Handler {


Handler successor= new FanHandler();
public void handleRequest(String s) {
successor.handleRequest(s);

FanHandler.java

public class FanHandler implements Handler {


Handler successor=new ComplaintHandler();
public void handleRequest(String s) {
if(s.equalsIgnoreCase("Fan")){
replyMail();
}else{
successor.handleRequest(s);
}
}
public void replyMail(){
System.out.println("Thanks for the wishes");
System.out.println("Regards,");
System.out.println("CEO");
}

ComplaintHandler.java
public class ComplaintHandler implements Handler{
Handler successor=new NewLocHandler();
public void handleRequest(String s) {
if(s.equalsIgnoreCase("Complaint")){
action();
}else{
successor.handleRequest(s);
}
}
public void action(){
System.out.println("Your compalint has been forwarded. Action will be
taken at the earliest ");
}
}

53
NewLocHandler.java:

public class NewLocHandler implements Handler {


Handler successor=new SpamHandler();
public void handleRequest(String s) {
if(s.equalsIgnoreCase("New Location")){
respond();
}else{
successor.handleRequest(s);
}
}
public void respond(){
System.out.println("Machines will be placed at the location suggested at
the earliest");
}

SpamHandler.java:
public class SpamHandler implements Handler{
public void handleRequest(String s){
if(s.equalsIgnoreCase("Spam")){
System.out.println("Mail deleted");
} else{
System.out.println("Failure Delivery due to wrong subject");
}

References :
1. Gang of Four, design patterns

54

Das könnte Ihnen auch gefallen