Professional Documents
Culture Documents
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”.
1
in evaluating the benefits and costs involved in using the pattern. The
consequences for s/w often concern space and time trade-offs.
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:
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.
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.
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.
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
}
}
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
Common Usage:
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
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
In Java, iterator ( ) method is a factory method. This method returns the right type of
iterator for the collection being asked for it.
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:
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.
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.
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.
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:
Factory Class:
package factoryPattern;
String shareType;
public SharesDisplayFactory(String shareType){
this.shareType=shareType;
display().displayShares();
}
16
return new PurchaseDisplay();
}else{
return new DisplayGrantedShares();
}
}
Client Class:
package factoryPattern;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
new SharesDisplayFactory(shareType);
}
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:
Description:
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:
18
You typically use the following to implement the Abstract Factory pattern:
Benefits:
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.
Applicability
20
Consequences
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;
package abstractfactory;
public class Server extends Computer{
21
public Parts getProcessor() {
return new Parts("Celeron");
}
}
public class ComputerType {
private Computer comp;
System.out.println("Monitor:
"+computer.getMonitor().getSpecification());
System.out.println("RAM:
"+computer.getRAM().getSpecification());
System.out.println("Processor:
"+computer.getProcessor().getSpecification());
}
22
System.out.println("Monitor:
"+computer.getMonitor().getSpecification());
System.out.println("RAM:
"+computer.getRAM().getSpecification());
System.out.println("Processor:
"+computer.getProcessor().getSpecification());
}
Prototype Pattern
Intent:
"Specify the kinds of objects to create using a prototypical instance, and create new
objects by copying this prototype.”
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.
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.
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
27
Collaborations
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.
Implementation
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.
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:
30
protected String bassLine;
return super.clone();
return bassLevel;
this.bassLevel = bassLevel;
return bassLine;
this.bassLine = bassLine;
31
public int getDrumLevel() {
return drumLevel;
this.drumLevel = drumLevel;
return drumTrack;
this.drumTrack = drumTrack;
return guitarLevel;
this.guitarLevel = guitarLevel;
32
}
return guitarTrack;
this.guitarTrack = guitarTrack;
Concrete Prototypes:
PEPPERSEED:
public PepperSeed() {
drumLevel = 5;
bassLevel = 7;
guitarLevel = 4;
33
TAXI:
public Taxi() {
drumLevel = 6;
bassLevel = 9;
guitarLevel = 4;
BACKAYARD:
public BackYard() {
drumLevel = 7;
bassLevel = 8;
guitarLevel = 7;
34
}
PROTOTYPE MANAGER:
import java.util.Hashtable;
HotRhytm rhythmToMix;
HotRhytm selectedRhythm;
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) {
e.printStackTrace();
return rhythmToMix;
CLIENT:
System.out.println("Guitarlevel: "+rhythmType.getGuitarLevel());
System.out.println("BassLine: "+rhythmType.getBassLine());
36
System.out.println("Drum Track: "+rhythmType.getDrumTrack());
OUTPUT:
package com.apwebco.patterns.gof.prototype;
37
private int numberOfPages;
38
ProductCache.loadCache();
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.
39
Builder Pattern
Intent:
“Separate the construction of a complex object from its representation so that the same
construction process can create different representations.”
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.
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.
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.
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:
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.
• 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");
}
44
SpicyPizzaBuilder.java:
public class SpicyPizzaBuilder extends PizzaBuilder {
public void buildSauce() {
pizza.setSauce("chilly");
}
}
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 {
Client :Customer.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
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.
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.
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:
Handler interface:
Handler.java:
public interface Handler {
public void handleRequest(String s);
52
Concrete Handlers:
Chain Instantiator:MailHandler.java
FanHandler.java
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:
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