Chapter On 5 Design Patterns
Chapter On 5 Design Patterns
2. From a given list, select the most appropriate pattern for a given scenario and
demonstrate its applicability
3. From a list, select the most appropriate pattern for a given scenario. Patterns
are limited to those documented in the book - Gamma, Erich; Richard Helm,
Ralph Johnson, and John Vlissides (1995). Design Patterns: Elements of Reusable
Object-Oriented Software and are named using the names given in that book.
4. Understand the idea of refactoring and re-factor software code to Design Patterns
Christopher Alexander talking about buildings and towns ”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 ” Alexander, et al., A
Pattern Language. Oxford University Press, 1977
Patterns can have different levels of abstraction. In Design Patterns (the book), Patterns
are not classes, Patterns are not frameworks. Instead, Patterns are descriptions of
communicating objects and classes that are customized to solve a general design problem
in a particular context
So, patterns are formalized solutions to design problems. They describe techniques for
maximizing flexibility, extensibility, abstraction, etc. These solutions can typically be
translated to code in a straight forward manner.
It is important to note the fact that Patterns makes our life easy by giving guidelines
to apply in a given context and for a specific problem.
67
Design Patterns and Software Refactoring 68
Pattern Name
This is more than just a handle for referring to the pattern. Each name adds to a
designers vocabulary. It enables the discussion of design at a higher abstraction.
The Problem
This gives a detailed description of the problem addressed by the pattern. It describes
when to apply a pattern, often with a list of preconditions.
The Solution This describes the elements that make up the design, their relation-
ships,responsibilities, and collaborations. It does not describe a concrete solution. In-
stead a template to be applied in many situations
The consequences
This describes the results and tradeoffs of applying the pattern. It is critical for evalu-
ating design alternatives Typically include impact on flexibility, extensibility, or porta-
bility, Space and Time tradeoffs, Language and Implementation issues
� Creational
� Structural
� Behavioural
4. Collaborations
5. Consequences
6. Implementation
7. Sample Code
8. Known Uses
9. Related Patterns
The selected pattern is Singleton because of its simplicity to grasp and understand.
Design Patterns and Software Refactoring 69
7.5.1 Singleton
Intent
Ensure a class has only one instance, and provide a global point of access to it
Motivation
Some classes represent objects where multiple instances do not make sense or can lead
to a security risk (e.g. Java security managers) and memory or heap overload
Applicability
Use the Singleton pattern when there must be exactly one instance of a class, and it must
be accessible to clients from a well-known access point, when the sole instance should
be extensible by subclassing, and clients should be able to use an extended instance
without modifying their code
Structure
Participants
Collaborations
Consequences
Controlled access to sole instance. Reduced name space (versus global variables) Permits
a variable number of instances (if desired)
Implementation
private Singleton () {
}
Usage
Design Patterns and Software Refactoring 70
Output:
There are totally 23 design patterns in GoF ( Gang of Four). All these 23 design patterns
are mapped to 3 main categories:
2. Structural patterns : Makes Objects available to other class by changing the in-
terfaces or contract.
3. Behavioral patterns: Deals with object state changes and it’s interaction with
other classes/objects.
Design Patterns and Software Refactoring 71
The following section has exercise for the 23 GOF patterns. Create a java application
and folders as shown in the diagram below.
And then do the exercises below. Record your output in the log book or word document.
zip your application together with your output and upload to WEBCT
The basic form of object creation could result in design problems or added complexity
to the design. Creational design patterns solve this problem by somehow controlling this
object creation.
Creational patterns involve the construction of new objects by often hiding the construc-
tors in the classes being created, and provides alternate methods to return instances of
the desired class.
All the creational patterns define the best possible way in which an object can be created
considering reuse and changeability. These describes the best way to handle instantia-
tion.
Hard coding the actual instantiation is a pitfall and should be avoided if reuse and
changeability are desired. In such scenarios, we can make use of creational patterns to
give this a more general and flexible approach.
1. Singleton
Design Patterns and Software Refactoring 72
2. Factory Method
3. Abstract Factory
4. Builder Pattern
5. Prototype
This is another version of the simplest Design Pattern you will ever come across. Essen-
tially. a singleton is a class that is instantiated only once.
This is typically accomplished by creating a static field in the class representing the
class. A static method exists on the class to obtain the instance of the class and is
typically named something such as getInstance(). The creation of the object referenced
by the static field can be done either when the class is initialized or the first time that
getInstance() is called. The singleton class typically has a private constructor to prevent
the singleton class from being instantiated via a constructor. Rather, the instance of
the singleton is obtained via the static getInstance() method.
/�
� To c h a n g e t h i s t e m p l a t e , c h o o s e T o o l s | T e m p l a t e s
� and open t h e t e m p l a t e i n t h e e d i t o r .
�/
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . s i n g l e t o n ;
/� �
�
� @author b o n i f a c e
�/
public class SingletonExample {
private SingletonExample () {
}
public void s a y H e l l o () {
System . out . println (” Hello ”) ;
}
}
Design Patterns and Software Refactoring 73
The MainDriver class obtains a SingletonExample singleton class via the call to the
static [Link](). We call the sayHello() method on the singleton
class.
/�
� To c h a n g e t h i s t e m p l a t e , c h o o s e T o o l s | T e m p l a t e s
� and open t h e t e m p l a t e i n t h e e d i t o r .
�/
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . s i n g l e t o n ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
The Factory Pattern (also known as the Factory Method Pattern ) is a creational
design pattern. A factory is a Java class that is used to encapsulate object creation
code. A factory class instantiates and returns a particular type of object based on data
passed to the factory. The different types of objects that are returned from a factory
typically are subclasses of a common parent class.
The data passed from the calling code to the factory can be passed either when the
factory is created or when the method on the factory is called to create an object. This
creational method is often called something such as getInstance or getClass .
As a simple example, let’s create an AnimalFactory class that will return an animal
object based on some data input. To start, here is an abstract Animal class. The
factory will return an instantiated subclass of Animal. Animal has a single abstract
method, makeSound().
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . f a c t o r y m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public abstract class Animal {
public abstract String makeSound () ;
Design Patterns and Software Refactoring 74
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . f a c t o r y m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public class Dog extends Animal {
@Override
public String makeSound () {
r e t u r n ”Woof” ;
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . f a c t o r y m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public class Cat extends Animal {
@Override
public String makeSound () {
r e t u r n ”Meow” ;
}
}
Now, let’s implement our factory. We will call our factory’s object creation method
getAnimal. This method takes a String as a parameter. If the String is ”canine”, it
returns a Dog object. Otherwise, it returns a Cat object.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . f a c t o r y m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public class AnimalFactory {
The MainDriver class demonstrates the use of our factory. It creates an AnimalFactory
factory. The factory creates an Animal object and then another Animal object. The first
object is a Cat and the second object is a Dog. The output of each object’s makeSound()
method is displayed.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . f a c t o r y m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
Animal a1 = a n i m a l F a c t o r y . g e t A n i m a l ( ” f e l i n e ” ) ;
S y s t e m . o u t . p r i n t l n ( ” a1 sound : ” + a 1 . m a k e S o u n d ( ) ) ;
Animal a2 = a n i m a l F a c t o r y . g e t A n i m a l ( ” canine ” ) ;
S y s t e m . o u t . p r i n t l n ( ” a2 sound : ” + a 2 . m a k e S o u n d ( ) ) ;
Design Patterns and Software Refactoring 75
}
}
Notice that the factory has encapsulated our Animal object creation code, thus resulting
in clean code in Demo, the class that creates the factory. Additionally, notice the use of
polymorphism. We obtain different Animal objects (Cat and Dog) based on data passed
to the factory.
Note that it is common to pass data that determines the type of object to be created
to the factory when the factory is created (via the factory constructor). However, if
multiple objects are being created by the factory, it may make sense to pass this data to
the factory’s creational method rather than to the constructor, since it might not make
sense to create a new factory object each time we wanted to have the factory instantiate
a new object.
A factory may also be used in conjunction with the singleton pattern. It is common to
have a singleton return a factory instance. To do this, we could replace:
AnimalFactory a n i m a l F a c t o r y = new A n i m a l F a c t o r y ( ) ;
with
Redo the AnimalFactory to make it a singleton, run the code and include
you new modified code in your submission.
As an example, you could have a BMW factory that returns car part objects (seats, air
filters, etc) associated with a BMW. You could also have a Toyota factory that returns car
part objects associated with a Toyota. We could create an abstract factory that returns
these different types of car factories depending on the car that we were interested in.
We could then obtain car part objects from the car factory. Via polymorphism, we can
use a common interface to get the different factories, and we could could then use a
common interface to get the different car parts.
Now, we’ll look at the code for a simple example of the Abstract Factory Design Pattern.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . a b s t r a c t f a c t o r y ;
/� �
�
� @author b o n i f a c e
�/
public class AbstractFactory {
SpeciesFactory is an abstract class with the getAnimal() abstract method. This method
returns an Animal object. The polymorphism of AbstractFactory is achieved because its
getSpeciesFactory() method returns a SpeciesFactory, regardless of the actual underlying
class. This polymorphism could also be achieved via an interface rather than an abstract
class.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . a b s t r a c t f a c t o r y ;
/� �
�
� @author b o n i f a c e
�/
public abstract class SpeciesFactory {
public abstract Animal getAnimal ( String type ) ;
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . a b s t r a c t f a c t o r y ;
/� �
�
� @author b o n i f a c e
�/
public class MammalFactory extends SpeciesFactory {
@Override
public Animal getAnimal ( String type ) {
i f ( ” dog ” . e q u a l s ( t y p e ) ) {
r e t u r n new D o g ( ) ;
Design Patterns and Software Refactoring 77
} else {
r e t u r n new C a t ( ) ;
}
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . a b s t r a c t f a c t o r y ;
/� �
�
� @author b o n i f a c e
�/
public class ReptileFactory extends SpeciesFactory {
@Override
public Animal getAnimal ( String type ) {
i f ( ” snake ” . e q u a l s ( t y p e ) ) {
r e t u r n new S n a k e ( ) ;
} else {
r e t u r n new T y r a n n o s a u r u s ( ) ;
}
}
}
Animal is an abstract class with the makeSound() abstract method. Subclasses of Ani-
mal implement the makeSound() method.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . f a c t o r y m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public abstract class Animal {
public abstract String makeSound () ;
}
Cat Class
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . f a c t o r y m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public class Cat extends Animal {
@Override
public String makeSound () {
r e t u r n ”Meow” ;
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . f a c t o r y m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public class Dog extends Animal {
@Override
public String makeSound () {
r e t u r n ”Woof” ;
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . f a c t o r y m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public class Cat extends Animal {
@Override
public String makeSound () {
return ” Hiss ” ;
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . f a c t o r y m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public class Tyrannosaurus extends Animal {
@Override
public String makeSound () {
r e t u r n ” Roar ” ;
}
}
The DriverMain class contains our main() method. It creates an AbstractFactory object.
From the AbstractFactory, we obtain a SpeciesFactory (a ReptileFactory) and get two
Animal objects (Tyrannosaurus and Snake) from the SpeciesFactory. After this, we
obtain another SpeciesFactory (a MammalFactory) and then obtain two more Animal
objects (Dog and Cat).
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . a b s t r a c t f a c t o r y ;
/� �
�
� @author b o n i f a c e
�/
public abstract class MainDriver {
S p e c i e s F a c t o r y s p e c i e s F a c t o r y 2 = a b s t r a c t F a c t o r y . g e t S p e c i e s F a c t o r y ( ”mammal” ) ;
A n i m a l a 3 = s p e c i e s F a c t o r y 2 . g e t A n i m a l ( ” dog ” ) ;
S y s t e m . o u t . p r i n t l n ( ” a3 sound : ” + a 3 . m a k e S o u n d ( ) ) ;
Animal a4 = s p e c i e s F a c t o r y 2 . g e t A n i m a l ( ” cat ” ) ;
S y s t e m . o u t . p r i n t l n ( ” a4 sound : ” + a 4 . m a k e S o u n d ( ) ) ;
}
}
Notice the use of polymorphism. We obtain different factories via the common Species-
Factory superclass. We also obtain different animals via the common Animal superclass.
Design Patterns and Software Refactoring 79
The builder pattern is a creational design pattern used to assemble complex objects.
With the builder pattern, the same object construction process can be used to create
different objects. The builder has 4 main parts: a Builder, Concrete Builders, a Director,
and a Product.
A Builder is an interface (or abstract class) that is implemented (or extended) by Con-
crete Builders. The Builder interface sets forth the actions (methods) involved in as-
sembling a Product object. It also has a method for retrieving the Product object (ie,
getProduct()). The Product object is the object that gets assembled in the builder
pattern.
Concrete Builders implement the Builder interface (or extend the Builder abstract class).
A Concrete Builder is responsible for creating and assembling a Product object. Different
Concrete Builders create and assemble Product objects differently.
A Director object is responsible for constructing a Product. It does this via the Builder
interface to a Concrete Builder. It constructs a Product via the various Builder methods.
There are various uses of the builder pattern. For one, if we’d like the construction
process to remain the same but we’d like to create a different type of Product, we can
create a new Concrete Builder and pass this to the same Director. If we’d like to alter
the construction process, we can modify the Director to use a different construction
process.
Now, let’s look at an example of the builder pattern. Our example will build different
kinds of restaurant meals.
First off, our Product will be a Meal class, which represents food items in a meal. It
represents a drink, main course, and side item.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . b u i l d e r ;
/� �
�
� @author b o n i f a c e
�/
public class Meal {
Design Patterns and Software Refactoring 80
public void s e t M a i n C o u r s e ( S t r i n g m a i n C o u r s e ) {
this . mainCourse = mainCourse ;
}
Our Builder interface is MealBuilder. It features methods used to build a meal and a
method to retrieve the meal.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . b u i l d e r ;
/� �
�
� @author b o n i f a c e
�/
public interface MealBuilder {
public void b u i l d D r i n k () ;
Our first Concrete Builder is ItalianMealBuilder. Its constructor creates a meal. Its
methods are implemented to build the various parts of the meal. It returns the meal via
getMeal().
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . b u i l d e r ;
/� �
�
� @author b o n i f a c e
�/
public class ItalianMealBuilder implements MealBuilder {
public ItalianMealBuilder () {
m e a l = new M e a l ( ) ;
}
@Override
public void b u i l d D r i n k () {
m e a l . s e t D r i n k ( ” r e d wine ” ) ;
}
@Override
public void b u i l d M a i n C o u r s e () {
meal . setMainCourse (” pizza ”) ;
}
@Override
public void b u i l d S i d e () {
m e a l . s e t S i d e ( ” bread ” ) ;
}
Design Patterns and Software Refactoring 81
@Override
public Meal getMeal () {
return meal ;
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . b u i l d e r ;
/� �
�
� @author b o n i f a c e
�/
public class JapaneseMealBuilder implements MealBuilder {
public JapaneseMealBuilder () {
m e a l = new M e a l ( ) ;
}
@Override
public void b u i l d D r i n k () {
meal . s e t D r i n k ( ” sake ” ) ;
}
@Override
public void b u i l d M a i n C o u r s e () {
meal . s e t M a i n C o u r s e ( ” chicken t e r i y a k i ” ) ;
}
@Override
public void b u i l d S i d e () {
m e a l . s e t S i d e ( ” miso soup ” ) ;
}
@Override
public Meal getMeal () {
return meal ;
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . b u i l d e r ;
/� �
�
� @author b o n i f a c e
�/
public class MealDirector {
The MainDriver class lets us demonstrate our builder pattern. First, our director builds
an Italian meal. An ItalianMealBuilder is passed to the MealDirector’s constructor.
The meal is constructed via [Link](). The meal is obtained from
Design Patterns and Software Refactoring 82
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . b u i l d e r ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
M e a l B u i l d e r m e a l B u i l d e r = new I t a l i a n M e a l B u i l d e r ( ) ;
M e a l D i r e c t o r m e a l D i r e c t o r = new M e a l D i r e c t o r ( m e a l B u i l d e r ) ;
mealDirector . constructMeal () ;
Meal meal = mealDirector . getMeal () ;
S y s t e m . o u t . p r i n t l n ( ” meal i s : ” + m e a l ) ;
m e a l B u i l d e r = new J a p a n e s e M e a l B u i l d e r ( ) ;
m e a l D i r e c t o r = new M e a l D i r e c t o r ( m e a l B u i l d e r ) ;
mealDirector . constructMeal () ;
meal = mealDirector . getMeal () ;
S y s t e m . o u t . p r i n t l n ( ” meal i s : ” + m e a l ) ;
}
}
Notice that if we’d like to create a new type of meal, we can do so by implementing
a new Concrete Builder (ie, SwedishMealBuilder, FrenchMealBuilder, etc), which we’d
pass to the MealDirector. If we’d like the meal to be constructed of different parts (ie,
no drink), we can alter the construction process in MealDirector. Thus, construction
process has been separated to the Director, and the data representation is controlled by
the Concrete Builders that implement the Builder interface.
Create a two extra meals for your Example and include the code in your
submission
The prototype pattern is a creational design pattern. In the prototype pattern, a new
object is created by cloning an existing object. In Java, the clone() method is an
implementation of this design pattern. The prototype pattern can be a useful way of
creating copies of objects.
One example of how this can be useful is if an original object is created with a resource
such as a data stream that may not be available at the time that a clone of the object
is needed.
Another example is if the original object creation involves a significant time commitment,
such as reading data from a database or over a network. An added benefit of the
Design Patterns and Software Refactoring 83
prototype pattern is that it can reduce class proliferation in a project by avoiding factory
proliferation.
Normally in Java, if you’d like to use cloning (ie, the prototype pattern), you can utilize
the clone() method and the Cloneable interface. By default, clone() performs a shallow
copy
However, we can implement our own prototype pattern. To do so, we’ll create a Proto-
type interface that features a doClone() method.
The Person class implements the doClone() method. This method creates a new Person
object and clones the name field. It returns the newly cloned Person object.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . p r o t o t y p e ;
/� �
�
� @author b o n i f a c e
�/
public class Person implements Prototype {
String name ;
@Override
public Prototype doClone () {
r e t u r n new P e r s o n ( n a m e ) ;
}
The Dog class also implements the doClone() method. This method creates a new Dog
object and clones the sound field. The cloned Dog object is returned.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . p r o t o t y p e ;
/� �
�
� @author b o n i f a c e
�/
public class D o g implements Prototype {
String sound ;
@Override
public Prototype doClone () {
r e t u r n new D o g ( s o u n d ) ;
}
The MainDriver creates a Person object and then clones it to a second Person object.
It then creates a Dog object and clones it to a second Dog object.
Design Patterns and Software Refactoring 84
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . c r e a t i o n a l . p r o t o t y p e ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
P e r s o n p e r s o n 1 = new P e r s o n ( ” Fred ” ) ;
S y s t e m . out . p r i n t l n ( ” person 1: ” + p e r s o n 1 ) ;
Person person2 = ( Person ) person1 . doClone () ;
S y s t e m . out . p r i n t l n ( ” person 2: ” + p e r s o n 2 ) ;
D o g d o g 1 = new D o g ( ”Wooof ! ” ) ;
S y s t e m . o u t . p r i n t l n ( ” dog 1 : ” + d o g 1 ) ;
Dog dog2 = ( Dog ) dog1 . doClone () ;
S y s t e m . o u t . p r i n t l n ( ” dog 2 : ” + d o g 2 ) ;
}
}
In software engineering, structural design patterns are design patterns that ease the
design by identifying a simple way to realize relationships between entities.
A structural design pattern serves as a blueprint for how different classes and objects
are combined to form larger structures. Unlike creational patterns, which are mostly
different ways to fulfill the same fundamental purpose, each structural pattern has a
different purpose.
Structural Patterns describe how objects and classes can be combined to form structures.
We distinguish between object patterns and class patterns.
The difference is that class patterns describe relationships and structures with the help
of inheritance. Object patterns, on other hand, describe how objects can be associated
and aggregated to form larger, more complex structures.
In some sense, structural patterns are similar to the simpler concept of data structures.
However, structural design patterns also specify the methods that connect objects, not
merely the references between them. Furthermore, data structures are fairly static
entities. They only describe how data is arranged in the structure.
A structural design pattern also describes how data moves through the pattern. Struc-
tural class patterns use inheritance to combine the interfaces or implementations of
multiple classes.
1. Adapter pattern
2. Composite pattern
3. Proxy pattern
4. Flyweight Pattern
5. Facade Pattern
6. Bridge Pattern
7. Decorator Pattern
Design Patterns and Software Refactoring 86
The adapter pattern is a structural design pattern. In the Adapter pattern, a wrapper
class (ie, the adapter) is used to translate requests from it to another class (ie, the
adaptee). In effect, an adapter provides particular interactions with an adaptee that are
not offered directly by the adaptee.
The adapter pattern takes two forms. In the first form, a ”class adapter” utilizes inher-
itance. The class adapter extends the adaptee class and adds the desired methods to
the adapter. These methods can be declared in an interface (ie, the ”target” interface).
In the second form, an ”object adapter” utilizes composition. The object adapter con-
tains an adaptee and implements the target interface to interact with the adaptee.
Now let’s look at simple examples of a class adapter and an object adapter. First, we
have an adaptee class named CelciusReporter. It stores a temperature value in Celcius.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . a d a p t e r ;
/� �
�
� @author b o n i f a c e
�/
public class CelciusReporter {
double temperatureInC ;
public CelciusReporter () {
}
p u b l i c double g e t T e m p e r a t u r e ( ) {
return temperatureInC ;
}
p u b l i c void s e t T e m p e r a t u r e ( double t e m p e r a t u r e I n C ) {
this . temperatureInC = temperatureInC ;
}
}
Here is our target interface that will be implemented by our adapter. It defines actions
that our adapter will perform.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . a d a p t e r ;
/� �
�
� @author b o n i f a c e
�/
public interface TemperatureInfo {
Design Patterns and Software Refactoring 87
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . a d a p t e r ;
/� �
�
� @author b o n i f a c e
�/
// example o f a c l a s s a d a p t e r
public class TemperatureClassReporter extends CelciusReporter implements TemperatureInfo {
@Override
p u b l i c double g e t T e m p e r a t u r e I n C ( ) {
return temperatureInC ;
}
@Override
p u b l i c double g e t T e m p e r a t u r e I n F ( ) {
return cToF ( temperatureInC ) ;
}
@Override
p u b l i c void s e t T e m p e r a t u r e I n C ( double t e m p e r a t u r e I n C ) {
this . temperatureInC = temperatureInC ;
}
@Override
p u b l i c void s e t T e m p e r a t u r e I n F ( double t e m p e r a t u r e I n F ) {
this . temperatureInC = fToC ( temperatureInF ) ;
}
p r i v a t e double f T o C ( double f ) {
return ( ( f − 32) � 5 / 9) ;
}
p r i v a t e double c T o F ( double c ) {
return ( ( c � 9 / 5) + 32) ;
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . a d a p t e r ;
/� �
�
� @author b o n i f a c e
�/
// example o f an o b j e c t a d a p t e r
public class TemperatureObjectReporter implements TemperatureInfo {
CelciusReporter celciusReporter ;
public TemperatureObjectReporter () {
c e l c i u s R e p o r t e r = new C e l c i u s R e p o r t e r ( ) ;
}
@Override
p u b l i c double g e t T e m p e r a t u r e I n C ( ) {
return celciusReporter . getTemperature () ;
}
@Override
p u b l i c double g e t T e m p e r a t u r e I n F ( ) {
return cToF ( celciusReporter . getTemperature () ) ;
}
Design Patterns and Software Refactoring 88
@Override
p u b l i c void s e t T e m p e r a t u r e I n C ( double t e m p e r a t u r e I n C ) {
celciusReporter . setTemperature ( temperatureInC ) ;
}
@Override
p u b l i c void s e t T e m p e r a t u r e I n F ( double t e m p e r a t u r e I n F ) {
celciusReporter . setTemperature ( fToC ( temperatureInF ) ) ;
}
p r i v a t e double f T o C ( double f ) {
return ( ( f − 32) � 5 / 9) ;
}
p r i v a t e double c T o F ( double c ) {
return ( ( c � 9 / 5) + 32) ;
}
The MainDriver class is a client class that demonstrates the adapter pattern. First,
it creates a TemperatureClassReporter object and references it via a TemperatureInfo
reference. It demonstrates calls to the class adapter via the TemperatureInfo interface.
After this, it creates a TemperatureObjectReporter object and references it via the same
TemperatureInfo reference. It then demonstrates calls to the object adapter.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . a d a p t e r ;
/� �
�
� @author b o n i f a c e
�/
public class DriverMain {
// c l a s s a d a p t e r
S y s t e m . out . p r i n t l n ( ” c l a s s adapter t e s t ” ) ;
T e m p e r a t u r e I n f o t e m p I n f o = new T e m p e r a t u r e C l a s s R e p o r t e r ( ) ;
testTempInfo ( tempInfo ) ;
// o b j e c t a d a p t e r
S y s t e m . o u t . p r i n t l n ( ”\ n o b j e c t adapter t e s t ” ) ;
t e m p I n f o = new T e m p e r a t u r e O b j e c t R e p o r t e r ( ) ;
testTempInfo ( tempInfo ) ;
public s t a t i c void t e s t T e m p I n f o ( T e m p e r a t u r e I n f o t e m p I n f o ) {
tempInfo . setTemperatureInC (0) ;
S y s t e m . o u t . p r i n t l n ( ” temp i n C : ” + t e m p I n f o . g e t T e m p e r a t u r e I n C ( ) ) ;
S y s t e m . o u t . p r i n t l n ( ” temp i n F : ” + t e m p I n f o . g e t T e m p e r a t u r e I n F ( ) ) ;
The composite pattern is a structural design pattern. In the composite pattern, a tree
structure exists where identical operations can be performed on leaves and nodes. A
node in a tree is a class that can have children. A node class is a ’composite’ class. A leaf
in a tree is a ’primitive’ class that does not have children. The children of a composite
can be leaves or other composites.
The leaf class and the composite class share a common ’component’ interface that defines
the common operations that can be performed on leaves and composites. When an
operation on a composite is performed, this operation is performed on all children of the
composite, whether they are leaves or composites. Thus, the composite pattern can be
used to perform common operations on the objects that compose a tree.
The Gang of Four description of the composite pattern defines a client’s interaction with
the tree struture via a Component interface, where this interface includes the common
operations on the composite and leaf classes, and the add/remove/get operations on the
composites of the tree. This seems slightly awkward since a leaf does not implement the
add/remove/get operations. In Java it makes more sense to define the common leaf/com-
posite operations on a Component interface, but to put the add/remove/get composite
operations in a separate interface or to simply implement them in the composite class.
Now we’ll look at an example of the composite pattern. First, we’ll declare a Component
interface that declares the operations that are common for the composite class and the
leaf class. This allows us to perform operations on composites and leaves using one
standard interface.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . c o m p o s i t e ;
/� �
�
� @author b o n i f a c e
Design Patterns and Software Refactoring 90
�/
public interface Component {
The Leaf class has a name field and implements the sayHello() and sayGoodbye() meth-
ods of the Component interface by outputting messages to standard output.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . c o m p o s i t e ;
/� �
�
� @author b o n i f a c e
�/
public class Leaf implements Component {
String name ;
@Override
public void s a y H e l l o () {
System . out . println ( name + ” leaf says hello ”) ;
}
@Override
public void s a y G o o d b y e () {
System . out . println ( name + ” leaf s a y s goodbye ” ) ;
}
}
The Composite class implements the Component interface. It implements the sayHello()
and sayGoodbye() methods by calling these same methods on all of its children, which
are Components (since they can be both Leaf objects and Composite objects, which
both implement the Component interface).
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . c o m p o s i t e ;
/� �
�
� @author b o n i f a c e
�/
public class Composite implements Component {
@Override
public void s a y H e l l o () {
for ( Component component : components ) {
component . sayHello () ;
}
}
@Override
public void s a y G o o d b y e () {
for ( Component component : components ) {
component . sayGoodbye () ;
}
}
public void r e m o v e ( C o m p o n e n t c o m p o n e n t ) {
components . remove ( component ) ;
}
p u b l i c L i s t <C o m p o n e n t > g e t C o m p o n e n t s ( ) {
return components ;
}
}
}
The MainDriver class demonstrates the composite pattern. It creates 5 Leaf objects. It
adds two of these two a Composite object and two of these to another Composite object.
It adds these two Composite objects and the last Leaf object to another Composite
object. It calls sayHello() on leaf1, then sayHello() on composite1, then sayHello() on
composite2, and then sayGoodbye() on composite3.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . c o m p o s i t e ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
C o m p o s i t e c o m p o s i t e 1 = new C o m p o s i t e ( ) ;
composite1 . add ( leaf1 ) ;
composite1 . add ( leaf2 ) ;
C o m p o s i t e c o m p o s i t e 2 = new C o m p o s i t e ( ) ;
composite2 . add ( leaf3 ) ;
composite2 . add ( leaf4 ) ;
Composite c o m p o s i t e 3 = new C o m p o s i t e ( ) ;
composite3 . add ( composite1 ) ;
composite3 . add ( composite2 ) ;
composite3 . add ( leaf5 ) ;
S y s t e m . o u t . p r i n t l n ( ”\ n C a l l i n g � s a y H e l l o � on c o m p o s i t e 1 ” ) ;
composite1 . sayHello () ;
S y s t e m . o u t . p r i n t l n ( ”\ n C a l l i n g � s a y H e l l o � on c o m p o s i t e 2 ” ) ;
composite2 . sayHello () ;
S y s t e m . o u t . p r i n t l n ( ”\ n C a l l i n g � sayGoodbye � on c o m p o s i t e 3 ” ) ;
composite3 . sayGoodbye () ;
}
}
The proxy pattern is a structural design pattern. In the proxy pattern, a proxy class is
used to control access to another class. The reasons for this control can vary. As one
example, a proxy may avoid instantiation of an object until the object is needed. This
can be useful if the object requires a lot of time or resources to create. Another reason
to use a proxy is to control access rights to an object. A client request may require
certain credentials in order to access the object.
Now, we’ll look at an example of the proxy pattern. First, we’ll create an abstract
class called Thing with a basic sayHello() message that includes the date/time that the
message is displayed.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . p r o x y ;
/� �
�
� @author b o n i f a c e
�/
public abstract class Thing {
public void s a y H e l l o () {
S y s t e m . o u t . p r i n t l n ( t h i s . g e t C l a s s ( ) . g e t S i m p l e N a m e ( ) + ” s a y s howdy a t ” + new D a t e ( ) ) ←�
;
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . p r o x y ;
/� �
�
� @author b o n i f a c e
�/
public c l a s s F a s t T h i n g extends Thing {
public FastThing () {
}
}
SlowThing also subclasses Thing. However, its constructor takes 5 seconds to execute.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . p r o x y ;
Design Patterns and Software Refactoring 93
/� �
�
� @author b o n i f a c e
�/
public class SlowThing extends Thing {
public SlowThing () {
try {
Thread . sleep (5000) ;
} catch ( I n t e r r u p t e d E x c e p t i o n e) {
e . printStackTrace () ;
}
}
}
The Proxy class is a proxy to a SlowThing object. Since a SlowThing object takes 5
seconds to create, we’ll use a proxy to a SlowThing so that a SlowThing object is only
created on demand. This occurs when the proxy’s sayHello() method is executed. It
instantiates a SlowThing object if it doesn’t already exist and then calls sayHello() on
the SlowThing object.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . p r o x y ;
/� �
�
� @author b o n i f a c e
�/
public class Proxy {
SlowThing slowThing ;
public Proxy () {
S y s t e m . o u t . p r i n t l n ( ” C r e a t i n g p r o x y a t ” + new D a t e ( ) ) ;
}
public void s a y H e l l o () {
if ( s l o w T h i n g == n u l l ) {
s l o w T h i n g = new S l o w T h i n g ( ) ;
}
slowThing . sayHello () ;
}
}
The MainDriver class demonstrates the use of our proxy. It creates a Proxy object and
then creates a FastThing object and calls sayHello() on the FastThing object. Next, it
calls sayHello() on the Proxy object.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . p r o x y ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
}
}
From the output, notice that creating the Proxy object and calling sayHello() on the
FastThing object occurred at a specific time , and calling sayHello() on the Proxy object
did not call sayHello() on the SlowThing object until another time. We can see that the
SlowThing creation was a time-consuming process. However, this did not slow down the
execution of our application until the SlowThing object was actually required. We can
Design Patterns and Software Refactoring 94
see here that the proxy pattern avoids the creation of time-consuming objects until they
are actually needed.
The flyweight pattern is a structural design pattern. In the flyweight pattern, instead of
creating large numbers of similar objects, objects are reused. This can be used to reduce
memory requirements and instantiation time and related costs. Similarities between
objects are stored inside of the objects, and differences are moved outside of the objects
and placed in client code. These differences are passed in to the objects when needed via
method calls on the objects. A Flyweight interface declares these methods. A Concrete
Flyweight class implements the Flyweight interface which is used to perform operations
based on external state and it also stores common state. A Flyweight Factory is used
create and return Flyweight objects.
Now, let’s look at an example of the flyweight design pattern. We’ll create a Flyweight
interface with a doMath() method that will be used to perform a mathematical operation
on two integers passed in as parameters.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . f l y w e i g h t ;
/� �
�
� @author b o n i f a c e
�/
public interface Flyweight {
field and displays the addition of a and b, which are external state values that are passed
in and used by the FlyweightAdder when doMath() is executed.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . f l y w e i g h t ;
/� �
�
� @author b o n i f a c e
�/
public class FlyweightAdder implements Flyweight {
String operation ;
public FlyweightAdder () {
o p e r a t i o n = ” adding ” ;
try {
Thread . sleep (3000) ;
} catch ( I n t e r r u p t e d E x c e p t i o n e) {
e . printStackTrace () ;
}
}
@Override
public void d o M a t h ( i n t a , i n t b ) {
S y s t e m . o u t . p r i n t l n ( o p e r a t i o n + ” ” + a + ” and ” + b + ” : ” + ( a + b ) ) ;
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . f l y w e i g h t ;
/� �
�
� @author b o n i f a c e
�/
public class FlyweightMultiplier implements Flyweight {
String operation ;
public FlyweightMultiplier () {
operation = ” multiplying ” ;
try {
Thread . sleep (3000) ;
} catch ( I n t e r r u p t e d E x c e p t i o n e) {
e . printStackTrace () ;
}
}
@Override
public void d o M a t h ( i n t a , i n t b ) {
S y s t e m . o u t . p r i n t l n ( o p e r a t i o n + ” ” + a + ” and ” + b + ” : ” + ( a � b)) ;
}
The FlyweightFactory class is our flyweight factory. It utilizes the singleton pattern so
that we only have once instance of the factory, which we obtain via its static getInstance()
method. The FlyweightFactory creates a hashmap pool of flyweights. If a request is
made for a flyweight object and that object doesn’t exist, it is created and placed in the
flyweight pool. The flyweight pool of the FlyweightFactory stores all the instances of
the different types of flyweights (ie, FlyweightAdder object, FlyweightMultiplier object,
etc). Thus, only one instance of each type is created, and this occurs on-demand.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . f l y w e i g h t ;
/� �
�
� @author b o n i f a c e
�/
public class FlyweightFactory {
Design Patterns and Software Refactoring 96
private FlyweightFactory () {
f l y w e i g h t P o o l = new H a s h M a p <S t r i n g , F l y w e i g h t >() ;
}
public static FlyweightFactory getInstance () {
i f ( f l y w e i g h t F a c t o r y == n u l l ) {
f l y w e i g h t F a c t o r y = new F l y w e i g h t F a c t o r y ( ) ;
}
return flyweightFactory ;
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . f l y w e i g h t ;
/� �
�
� @author b o n i f a c e
�/
When executing MainDriver, we see that it takes some seconds to create the Flyweigh-
tAdder object and the same thing happens for the FlyweightMultiplier object. After
this, no more delays occur since we keep reusing the flyweight objects rather than instan-
tiating new objects. This highlights how the flyweight pattern can be used to minimize
resource requirements by avoiding unnecessary object instantiations for similar objects.
Design Patterns and Software Refactoring 97
The facade pattern is a structural design pattern. In the facade pattern, a facade classes
is used to provide a single interface to set of classes. The Facade simplifies a clients
interaction with a complex system by localizing the interactions into a single interface.
As a result, the client can interact with a single object rather than being required to
interact directly in complicated ways with the objects that make up the subsystem.
As an example, supposed we have three horribly written classes. For based on the class
and method names (and the lack of documentation), it would be very difficult for a
client to interact with these classes.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . f a c a d e ;
/� �
�
� @author b o n i f a c e
�/
public class Class1 {
Class2’s doAnotherThing() method doubles the cube of an integer and returns it.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . f a c a d e ;
/� �
�
� @author b o n i f a c e
�/
public class Class2 {
Class3’s doMoreStuff() takes a Class1 object, a Class2 object, and an integer and returns
twice the sixth power of the integer.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . f a c a d e ;
/� �
�
� @author b o n i f a c e
�/
public class Class3 {
For a client unfamiliar with Class1, Class2, and Class3, it would be very difficult to
figure out how to interact with these classes. The classes interact and perform tasks in
unclear ways. As a result, we need to be able to simplify interaction with this system of
classes so that clients can interact with these classes in a simple, standardized manner.
We do this with the Facade class. The Facade class has three methods: cubeX(), cubeX-
Times2(), and xToSixthPowerTimes2(). The names of these methods clearly indicate
what they do, and these methods hide the interactions of Class1, Class2, and Class3
from client code.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . f a c a d e ;
/� �
�
� @author b o n i f a c e
�/
public class Facade {
The MainDriver class contains our client code. It creates a Facade object and then calls
its three methods with a parameter value of 3. It displays the returned results.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . f a c a d e ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
F a c a d e f a c a d e = new F a c a d e ( ) ;
int x = 3;
S y s t e m . o u t . p r i n t l n ( ”Cube o f ” + x + ” : ” + f a c a d e . c u b e X ( 3 ) ) ;
S y s t e m . o u t . p r i n t l n ( ”Cube o f ” + x + ” t i m e s 2 : ” + f a c a d e . c u b e X T i m e s 2 ( 3 ) ) ;
S y s t e m . o u t . p r i n t l n ( x + ” t o s i x t h power t i m e s 2 : ” + f a c a d e . x T o S i x t h P o w e r T i m e s 2 ( 3 ) ) ;
}
}
This example demonstrates how the facade pattern can be used to simplify interactions
with a system of classes by providing a single point of interaction with the subsystem
and hiding the complex details of subsystem interactions from client code. This is
accomplished with a Facade class.
Design Patterns and Software Refactoring 99
The bridge pattern is a structural design pattern. In the bridge pattern, we separate an
abstraction and its implementation and develop separate inheritance structures for both
the abstraction and the implementor. The abstraction is an interface or abstract class,
and the implementor is likewise an interface or abstract class. The abstraction contains
a reference to the implementor. Children of the abstraction are referred to as refined
abstractions, and children of the implementor are concrete implementors. Since we can
change the reference to the implementor in the abstraction, we are able to change the
abstraction’s implementor at run-time. Changes to the implementor do not affect client
code.
The bridge pattern can be demonstrated with an example. Suppose we have a Vehicle
class. We can extract out the implementation of the engine into an Engine class. We
can reference this Engine implementor in our Vehicle via an Engine field. We’ll declare
Vehicle to be an abstract class. Subclasses of Vehicle need to implement the drive()
method. Notice that the Engine reference can be changed via the setEngine() method.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . b r i d g e ;
/� �
�
� @author b o n i f a c e
�/
public abstract class Vehicle {
Engine engine ;
int weightInKilos ;
public void r e p o r t O n S p e e d ( i n t h o r s e p o w e r ) {
int ratio = weightInKilos / horsepower ;
i f ( r a t i o < 3) {
S y s t e m . o u t . p r i n t l n ( ”The v e h i c l e i s g o i n g a t a f a s t s p e e d . ” ) ;
} e l s e i f ( ( r a t i o >= 3 ) && ( r a t i o < 8 ) ) {
S y s t e m . o u t . p r i n t l n ( ”The v e h i c l e i s g o i n g an a v e r a g e s p e e d . ” ) ;
} else {
S y s t e m . o u t . p r i n t l n ( ”The v e h i c l e i s g o i n g a t a s l o w s p e e d . ” ) ;
}
}
BigBus is a subclass of Vehicle. It has a weight of 3000 kg. Its drive() method displays
a message, calls the engine’s go() method, and then calls reportOnSpeed() with the
horsepower of the engine to report on how fast the vehicle is moving.
Design Patterns and Software Refactoring 100
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . b r i d g e ;
/� �
�
� @author b o n i f a c e
�/
public class BigBus extends Vehicle {
@Override
public void dr ive () {
S y s t e m . o u t . p r i n t l n ( ” \nThe b i g bus is driving ”) ;
int h o r s e p o w e r = engine . go () ;
reportOnSpeed ( horsepower ) ;
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . b r i d g e ;
/� �
�
� @author b o n i f a c e
�/
public class SmallCar extends Vehicle {
@Override
public void dr ive () {
S y s t e m . o u t . p r i n t l n ( ” \nThe s m a l l car is driving ”) ;
int h o r s e p o w e r = engine . go () ;
reportOnSpeed ( horsepower ) ;
}
Our implementor interface is the Engine interface, which declares the go() method.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . b r i d g e ;
/� �
�
� @author b o n i f a c e
�/
public interface Engine {
public int go () ;
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . b r i d g e ;
/� �
�
� @author b o n i f a c e
�/
public class BigEngine implements Engine {
int horsepower ;
public BigEngine () {
horsepower = 350;
}
@Override
public int go () {
S y s t e m . o u t . p r i n t l n ( ”The b i g engine is running ” ) ;
return horsepower ;
}
}
Design Patterns and Software Refactoring 101
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . b r i d g e ;
/� �
�
� @author b o n i f a c e
�/
public class SmallEngine implements Engine {
int horsepower ;
public SmallEngine () {
horsepower = 100;
}
@Override
public int go () {
S y s t e m . o u t . p r i n t l n ( ”The s m a l l engine is running ” ) ;
return horsepower ;
}
}
The MainDriver class demonstrates our bridge pattern. We create a BigBus vehicle with
a SmallEngine implementor. We call the vehicle’s drive() method. Next, we change the
implementor to a BigEngine and once again call drive(). After this, we create a SmallCar
vehicle with a SmallEngine implementor. We call drive(). Next, we change the engine
to a BigEngine and once again call drive().
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . b r i d g e ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
V e h i c l e v e h i c l e = new B i g B u s ( new S m a l l E n g i n e ( ) ) ;
vehicle . drive () ;
v e h i c l e . s e t E n g i n e ( new B i g E n g i n e ( ) ) ;
vehicle . drive () ;
Notice that we were able to change the implementor (engine) dynamically for each
vehicle. These changes did not affect the client code in MainDriver. In addition, since
BigBus and SmallCar were both subclasses of the Vehicle abstraction, we were even able
to point the vehicle reference to a BigBus object and a SmallCar object and call the
same drive() method for both types of vehicles.
Design Patterns and Software Refactoring 102
The decorator pattern is a structural design pattern. Whereas inheritance adds func-
tionality to classes, the decorator pattern adds functionality to objects by wrapping
objects in other objects. Each time additional functionality is required, the object is
wrapped in another object. Java I/O streams are a well-known example of the decorator
pattern.
For the decorator pattern, we require a class that serves as the base object that we
add functionality to. This is a Concrete Component, and it implements a Component
interface. The Component interface declares the common operations that are to be
performed by the concrete component and all the decorators that wrap the concrete
component object. A Decorator is an abstract class that implements the Component
interface and contains a reference to a Component. Concrete Decorators are classes that
extend Decorator.
We can illustrate the decorator pattern with an example. We’ll start by creating an
Animal interface. The Animal interface is our component interface.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . d e c o r a t o r ;
/� �
�
� @author b o n i f a c e
�/
public interface Animal {
LivingAnimal implements Animal and is our concrete component. Its describe() method
displays a message indicating that it is an animal.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . d e c o r a t o r ;
Design Patterns and Software Refactoring 103
/� �
�
� @author b o n i f a c e
�/
public class LivingAnimal implements Animal {
@Override
public void d e s c r i b e () {
S y s t e m . o u t . p r i n t l n ( ” \ n I am an a n i m a l . ” ) ;
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . d e c o r a t o r ;
/� �
�
� @author b o n i f a c e
�/
public abstract class AnimalDecorator implements Animal {
Animal animal ;
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . d e c o r a t o r ;
/� �
�
� @author b o n i f a c e
�/
public class LegDecorator extends AnimalDecorator {
@Override
public void d e s c r i b e () {
animal . describe () ;
S y s t e m . o u t . p r i n t l n ( ” I have legs . ”) ;
dance () ;
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . d e c o r a t o r ;
/� �
�
� @author b o n i f a c e
�/
public class WingDecorator extends AnimalDecorator {
@Override
public void d e s c r i b e () {
animal . describe () ;
Design Patterns and Software Refactoring 104
S y s t e m . o u t . p r i n t l n ( ” I have w i n g s . ” ) ;
fly () ;
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . d e c o r a t o r ;
/� �
�
� @author b o n i f a c e
�/
public class GrowlDecorator extends AnimalDecorator {
@Override
public void d e s c r i b e () {
animal . describe () ;
growl () ;
}
The MainDriver class demonstrates the decorator design pattern. First, a LivingAnimal
object is created and is referenced via the Animal reference. The describe() method
is called. After this, we wrap the LivingAnimal in a LegDecorator object and once
again call describe. We can see that legs have been added. After that, we wrap the
LegDecorator in a WingDecorator, which adds wings to our animal. Later, we wrap the
animal in two GrowlDecorators. From the describe() output, we can see that two growl
messages are displayed since we wrapped the animal twice.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . s t r u c t u r a l . d e c o r a t o r ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
A n i m a l a n i m a l = new L i v i n g A n i m a l ( ) ;
animal . describe () ;
a n i m a l = new L e g D e c o r a t o r ( a n i m a l ) ;
animal . describe () ;
a n i m a l = new W i n g D e c o r a t o r ( a n i m a l ) ;
animal . describe () ;
a n i m a l = new G r o w l D e c o r a t o r ( a n i m a l ) ;
a n i m a l = new G r o w l D e c o r a t o r ( a n i m a l ) ;
animal . describe () ;
}
}
In this example, we just used the Animal reference to refer to the objects. Using this
approach, we could only access the shared operations of the Animal interface (ie, the
describe() method). Instead of referencing this interface, we could have referenced the
concrete decorator class. This would have exposed the unique functionality of the con-
crete decorator.
Design Patterns and Software Refactoring 105
In software engineering, behavioral design patterns are design patterns that identify
common communication patterns between objects and realize these patterns. By doing
so, these patterns increase flexibility in carrying out this communication.
A behavioral pattern explains how objects interact. It describes how different objects
and classes send messages to each other to make things happen and how the steps of a
task are divided among different objects. It describes how different objects work together
to accomplish a task
Where creational patterns mostly describe a moment of time (the instant of creation),
and structural patterns describe a more or less static structure, behavioral patterns
describe a process or a flow.
The interactions between cooperating objects should be such that they are communi-
cating while maintaining as loose coupling as possible. The loose coupling is the key to
n-tier architectures. In this, the implementation and the client should be loosely coupled
in order to avoid hard-coding and dependencies.
Behavioral class patterns use inheritance, subclassing, and polymorphism to adjust the
steps taken during a process. Behavioral class patterns focus on changing the exact
algorithm used or task performed depending on circumstances.
2. Mediator Pattern
4. Observer Pattern
5. Strategy Pattern
6. Command Pattern
7. State Pattern
8. Visitor Pattern
9. Iterator Pattern
The template method pattern is a behavioral class pattern. A behavioral class pat-
tern uses inheritance for distribution of behavior. In the template method pattern, a
method (the ’template method’) defines the steps of an algorithm. The implementation
of these steps (ie, methods) can be deferred to subclasses. Thus, a particular algorithm
is defined in the template method, but the exact steps of this algorithm can be defined
in subclasses. The template method is implemented in an abstract class. The steps
(methods) of the algorithm are declared in the abstract class, and the methods whose
implementations are to be delegated to subclasses are declared abstract.
Here is an example of the template method pattern. Meal is an abstract class with
a template method called doMeal() that defines the steps involved in a meal. We de-
clare the method as final so that it can’t be overridden. The algorithm defined by
doMeal() consists of four steps: prepareIngredients(), cook(), eat(), and cleanUp(). The
eat() method is implemented although subclasses can override the implementation. The
prepareIngredients(), cook(), and cleanUp() methods are are declared abstract so that
subclasses need to implement them.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . t e m p l a t e m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public abstract class Meal {
// t e m p l a t e method
public f i n a l void d o M e a l () {
prepareIngredients () ;
cook () ;
eat () ;
cleanUp () ;
}
The HamburgerMeal class extends Meal and implements Meal’s three abstract methods.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . t e m p l a t e m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public class HamburgerMeal extends Meal {
Design Patterns and Software Refactoring 107
@Override
public void p r e p a r e I n g r e d i e n t s () {
S y s t e m . o u t . p r i n t l n ( ” G e t t i n g b u r g e r s , buns , and f r e n c h fries ”) ;
}
@Override
public void cook () {
S y s t e m . o u t . p r i n t l n ( ” Cooking b u r g e r s on grill and fries i n oven ” ) ;
}
@Override
public void c l e a n U p () {
S y s t e m . o u t . p r i n t l n ( ” Throwing away p a p e r plates ”) ;
}
}
The CHeeseBurgerMeal class implements Meal’s three abstract methods and also over-
rides the eat() method.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . t e m p l a t e m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public c l a s s C h e e s e B u r g e r M e a l extends Meal {
@Override
public void p r e p a r e I n g r e d i e n t s () {
S y s t e m . o u t . p r i n t l n ( ” G e t t i n g ground b e e f and C h e e s e ” ) ;
}
@Override
public void cook () {
S y s t e m . o u t . p r i n t l n ( ” Cooking ground b e e f i n pan ” ) ;
}
@Override
public void eat () {
S y s t e m . o u t . p r i n t l n ( ”The C h e e s e B u r g e r s are tasty ”) ;
}
@Override
public void c l e a n U p () {
S y s t e m . o u t . p r i n t l n ( ” Doing t h e dishes ”) ;
}
The MainDriver creates a HamburgerMeal object and calls its doMeal() method. It
creates a TacoMeal object and calls doMeal() on the TacoMeal object.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . t e m p l a t e m e t h o d ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
M e a l m e a l 2 = new C h e e s e B u r g e r M e a l ( ) ;
meal2 . doMeal () ;
}
}
As you can see, the template method design pattern allows us to define the steps in an
algorithm and pass the implementation of these steps to subclasses.
Design Patterns and Software Refactoring 108
The mediator pattern is a behavioral object design pattern. The mediator pattern
centralizes communication between objects into a mediator object. This centralization is
useful since it localizes in one place the interactions between objects, which can increase
code maintainability, especially as the number of classes in an application increases.
Since communication occurs with the mediator rather than directly with other objects,
the mediator pattern results in a loose coupling of objects.
The classes that communicate with the mediator are known as Colleagues. The mediator
implementation is known as the Concrete Mediator. The mediator can have an interface
that spells out the communication with Colleages. Colleagues know their mediator, and
the mediator knows its colleagues.
Now, let’s look at an example of this pattern. We’ll create a Mediator class (without
implementing a mediator interface in this example). This mediator will mediate the
communication between two buyers (a Swedish buyer and a French buyer), an American
seller, and a currency converter.
The Mediator has references to the two buyers, the seller, and the converter. It has
methods so that objects of these types can be registered. It also has a placeBid()
method. This method takes a bid amount and a unit of currency as parameters. It
converts this amount to a dollar amount via communication with the dollarConverter.
It then asks the seller if the bid has been accepted, and it returns the answer.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . m e d i a t o r ;
/� �
�
� @author b o n i f a c e
�/
public class Mediator {
Buyer swedishBuyer ;
Buyer frenchBuyer ;
AmericanSeller americanSeller ;
DollarConverter dollarConverter ;
public Mediator () {
}
f l o a t d o l l a r A m o u n t = d o l l a r C o n v e r t e r . c o n v e r t C u r r e n c y T o D o l l a r s ( bid , unitOfCurrency ) ;
return americanSeller . isBidAccepted ( dollarAmount ) ;
}
}
Here is the Buyer class. The SwedishBuyer and FrenchBuyer classes are subclasses of
Buyer. The buyer has a unit of currency as a field, and it also has a reference to the
mediator. The Buyer class has a attemptToPurchase() method. This method submits
a bid to the mediator’s placeBid() method. It returns the mediator’s response.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . m e d i a t o r ;
/� �
�
� @author b o n i f a c e
�/
class Buyer {
Mediator mediator ;
String unitOfCurrency ;
The SwedishBuyer class is a subclass of Buyer. In the constructor, we set the unitOfCur-
rency to be ”krona”. We also register the SwedishBuyer with the mediator so that the
mediator knows about the SwedishBuyer object.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . m e d i a t o r ;
/� �
�
� @author b o n i f a c e
�/
class SwedishBuyer extends Buyer {
The FrenchBuyer class is similar to the SwedishBuyer class, except the unitOfCurrency
is ”euro”, and it registers with the mediator as the FrenchBuye
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . m e d i a t o r ;
/� �
�
� @author b o n i f a c e
�/
class FrenchBuyer extends Buyer {
In the constructor of the AmericanSeller class, the class gets a reference to the mediator
and the priceInDollars gets set. This is the price of some good being sold. The seller
registers with the mediator as the AmericanSeller. The seller’s isBidAccepted() method
Design Patterns and Software Refactoring 110
takes a bid (in dollars). If the bid is over the price (in dollars), the bid is accepted and
true is returned. Otherwise, false is returned.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . m e d i a t o r ;
/� �
�
� @author b o n i f a c e
�/
class AmericanSeller {
Mediator mediator ;
float priceInDollars ;
public boolean i s B i d A c c e p t e d ( f l o a t b i d I n D o l l a r s ) {
if ( b i d I n D o l l a r s >= p r i c e I n D o l l a r s ) {
S y s t e m . o u t . p r i n t l n ( ” S e l l e r a c c e p t s t h e b i d o f ” + b i d I n D o l l a r s + ” d o l l a r s \n” ) ;
return true ;
} else {
S y s t e m . o u t . p r i n t l n ( ” S e l l e r r e j e c t s t h e b i d o f ” + b i d I n D o l l a r s + ” d o l l a r s \n” ) ;
return f a l s e ;
}
}
}
The DollarConverter class is another colleague class. When created, it gets a reference
to the mediator and registers itself with the mediator as the DollarConverter. This class
has methods to convert amounts in euros and kronor to dollars.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . m e d i a t o r ;
/� �
�
� @author b o n i f a c e
�/
class DollarConverter {
Mediator mediator ;
public static f i n a l float DOLLAR_UNIT = 1.0 f ;
public static f i n a l float EURO_UNIT = 0.7 f ;
public static f i n a l float KRONA_UNIT = 8.0 f ;
French buyer starts bidding at 3 euros and keeps bidding in increments of 1.50 euros
until the bid is accepted.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . m e d i a t o r ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
public s t a t i c void main ( S t r i n g [ ] args ) {
M e d i a t o r m e d i a t o r = new M e d i a t o r ( ) ;
B u y e r s w e d i s h B u y e r = new S w e d i s h B u y e r ( m e d i a t o r ) ;
B u y e r f r e n c h B u y e r = new F r e n c h B u y e r ( m e d i a t o r ) ;
f l o a t se lli ngP ric eIn Dollar s = 10.0 f ;
A m e r i c a n S e l l e r a m e r i c a n S e l l e r = new A m e r i c a n S e l l e r ( m e d i a t o r , s e l l i n g P r i c e I n D o l l a r s ) ;
D o l l a r C o n v e r t e r d o l l a r C o n v e r t e r = new D o l l a r C o n v e r t e r ( m e d i a t o r ) ;
f l o a t swedishBidInKronor = 55.0 f ;
while ( ! swedishBuyer . a t t e m p t T o P u r c h a s e ( s w e d i s h B i d I n K r o n o r ) ) {
s w e d i s h B i d I n K r o n o r += 1 5 . 0 f ;
}
f l o a t frenchBidInEuros = 3.0 f ;
while ( ! frenchBuyer . a t t e m p t T o P u r c h a s e ( f r e n c h B i d I n E u r o s ) ) {
f r e n c h B i d I n E u r o s += 1 . 5 f ;
}
}
}
In this example of the mediator pattern, notice that all communication between our ob-
jects (buyers, seller, and converter) occurs via the mediator. The mediator pattern helps
reduce the number of object references needed (via composition) as classes proliferate
in a project as a project grows.
The chain of responsibility pattern is a behavioral object design pattern. In the chain
of responsibility pattern, a series of handler objects are chained together to handle
a request made by a client object. If the first handler can’t handle the request, the
request is forwarded to the next handler, and it is passed down the chain until the
request reaches a handler that can handle the request or the chain ends. In this pattern,
the client is decoupled from the actual handling of the request, since it does not know
what class will actually handle the request.
In this pattern, a Handler is an interface for handling a request and accessing a handler’s
successor. A Handler is implemented by a Concrete Handler. The Concrete Handler
will handle the request or pass it on to the next Concrete Handler. A Client makes the
request to the start of the handler chain.
Design Patterns and Software Refactoring 112
Now, let’s look at an example of the chain of responsibility pattern. Rather than an
interface, We’ll use an abstract base class as the handler so that subclasses can utilize
the implemented setSuccessor() method. This abstract class is called PlanetHandler.
Concrete handlers that subclass PlanetHandler need to implement the handleRequest()
method.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . c h a i n o f r e s p o n s i b i l i t y ;
/� �
�
� @author b o n i f a c e
�/
public abstract class PlanetHandler {
PlanetHandler successor ;
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . c h a i n o f r e s p o n s i b i l i t y ;
/� �
�
� @author b o n i f a c e
�/
public enum PlanetEnum {
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . c h a i n o f r e s p o n s i b i l i t y ;
/� �
�
� @author b o n i f a c e
�/
public class MercuryHandler extends PlanetHandler {
public void h a n d l e R e q u e s t ( P l a n e t E n u m r e q u e s t ) {
if ( r e q u e s t == P l a n e t E n u m . M E R C U R Y ) {
S y s t e m . o u t . p r i n t l n ( ” MercuryHandler h a n d l e s ” + r e q u e s t ) ;
S y s t e m . o u t . p r i n t l n ( ” Mercury i s h o t . \ n” ) ;
} else {
S y s t e m . o u t . p r i n t l n ( ” MercuryHandler doesn � t handle ” + r e q u e s t ) ;
i f ( s u c c e s s o r != n u l l ) {
successor . handleRequest ( request ) ;
}
}
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . c h a i n o f r e s p o n s i b i l i t y ;
/� �
�
� @author b o n i f a c e
�/
public class VenusHandler extends PlanetHandler {
public void h a n d l e R e q u e s t ( P l a n e t E n u m r e q u e s t ) {
if ( r e q u e s t == P l a n e t E n u m . V E N U S ) {
Design Patterns and Software Refactoring 113
S y s t e m . o u t . p r i n t l n ( ” VenusHandler h a n d l e s ” + r e q u e s t ) ;
S y s t e m . o u t . p r i n t l n ( ” Venus i s p o i s o n o u s . \ n” ) ;
} else {
S y s t e m . o u t . p r i n t l n ( ” VenusHandler d o e s n � t h a n d l e ” + r e q u e s t ) ;
i f ( s u c c e s s o r != n u l l ) {
successor . handleRequest ( request ) ;
}
}
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . c h a i n o f r e s p o n s i b i l i t y ;
/� �
�
� @author b o n i f a c e
�/
public class EarthHandler extends PlanetHandler {
public void h a n d l e R e q u e s t ( P l a n e t E n u m r e q u e s t ) {
if ( r e q u e s t == P l a n e t E n u m . E A R T H ) {
S y s t e m . o u t . p r i n t l n ( ” EarthHandler handles ” + r e q u e s t ) ;
S y s t e m . o u t . p r i n t l n ( ” E art h i s c o m f o r t a b l e . \ n” ) ;
} else {
S y s t e m . o u t . p r i n t l n ( ” EarthHandler doesn � t handle ” + r e q u e s t ) ;
i f ( s u c c e s s o r != n u l l ) {
successor . handleRequest ( request ) ;
}
}
}
}
The MainDriver is the client class. It creates the chain of handlers, starting with Mer-
curyHandler, then VenusHandler, and then EarthHandler. The setUpChain() method
returns the chain to main() via a PlanetHandler reference. Four requests are made of
the chain, where the requests are VENUS, MERCURY, EARTH, and JUPITER.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . c h a i n o f r e s p o n s i b i l i t y ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
return mercuryHandler ;
}
}
Notice that if a handler can’t handle the request, it passes the request on to the next
handler.
Notice that the last request made of the chain is JUPITER. This request is not handled
by any handlers, demonstrating that a request does not have to be handled by any
Design Patterns and Software Refactoring 114
handlers. If we had wanted to, we could have also written an OtherPlanets handler
and placed it at the end of the chain to handle planet requests not handled by other
previous handlers. This would demonstrate that we can make our handlers specific at
the beginning of the chain and more general at the end of the chain, thus handling
broader categories of requests as we approach the end of the chain.
The observer pattern is a behavioral object design pattern. In the observer pattern, an
object called the subject maintains a collection of objects called observers. When the
subject changes, it notifies the observers. Observers can be added or removed from the
collection of observers in the subject. The changes in state of the subject can be passed
to the observers so that the observers can change their own state to reflect this change.
The subject has an interface that defines methods for attaching and detaching observers
from the subject’s collection of observers. This interface also features a notification
method. This method should be called when the state of the subject changes. This
notifies the observers that the subject’s state has changed. The observers have an
interface with a method to update the observer. This update method is called for each
observer in the subject’s notification method. Since this communication occurs via an
interface, any concrete observer implementing the observer interface can be updated by
the subject. This results in loose coupling between the subject and the observer classes.
Now we’ll look at an example of the observer pattern. We’ll start by creating an interface
for the subject called WeatherSubject. This will declare three methods: addObserver(),
removeObserver(), and doNotify().
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . o b s e r v e r ;
/� �
�
� @author b o n i f a c e
�/
public interface WeatherSubject {
We’ll also create an interface for the observers called WeatherObserver. It features one
method, a doUpdate() method.
Design Patterns and Software Refactoring 115
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . o b s e r v e r ;
/� �
�
� @author b o n i f a c e
�/
public interface WeatherObserver {
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . o b s e r v e r ;
/� �
�
� @author b o n i f a c e
�/
public class WeatherStation implements WeatherSubject {
S e t <W e a t h e r O b s e r v e r > w e a t h e r O b s e r v e r s ;
int temperature ;
@Override
public void a d d O b s e r v e r ( W e a t h e r O b s e r v e r w e a t h e r O b s e r v e r ) {
weatherObservers . add ( weatherObserver ) ;
}
@Override
public void r e m o v e O b s e r v e r ( W e a t h e r O b s e r v e r w e a t h e r O b s e r v e r ) {
weatherObservers . remove ( weatherObserver ) ;
}
@Override
public void d o N o t i f y () {
I t e r a t o r <W e a t h e r O b s e r v e r > i t = w e a t h e r O b s e r v e r s . i t e r a t o r ( ) ;
while ( it . h a s N e x t () ) {
W e a t h e r O b s e r v e r w e a t h e r O b s e r v e r = it . next () ;
weatherObserver . doUpdate ( temperature ) ;
}
}
public void s e t T e m p e r a t u r e ( i n t n e w T e m p e r a t u r e ) {
S y s t e m . o u t . p r i n t l n ( ” \ nWeather s t a t i o n s e t t i n g temperature to ” + n e w T e m p e r a t u r e ) ;
temperature = newTemperature ;
doNotify () ;
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . o b s e r v e r ;
/� �
�
� @author b o n i f a c e
�/
public class WeatherCustomer1 implements WeatherObserver {
@Override
public void d o U p d a t e ( i n t t e m p e r a t u r e ) {
S y s t e m . o u t . p r i n t l n ( ” Weather c u s t o m e r 1 j u s t found out the temperature i s : ” + ←�
temperature ) ;
}
}
Design Patterns and Software Refactoring 116
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . o b s e r v e r ;
/� �
�
� @author b o n i f a c e
�/
public class WeatherCustomer2 implements WeatherObserver {
@Override
public void d o U p d a t e ( i n t t e m p e r a t u r e ) {
S y s t e m . o u t . p r i n t l n ( ” Weather c u s t o m e r 2 j u s t found out the temperature i s : ” + ←�
temperature ) ;
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . o b s e r v e r ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
W e a t h e r C u s t o m e r 1 w c 1 = new W e a t h e r C u s t o m e r 1 ( ) ;
W e a t h e r C u s t o m e r 2 w c 2 = new W e a t h e r C u s t o m e r 2 ( ) ;
weatherStation . addObserver ( wc1 ) ;
weatherStation . addObserver ( wc2 ) ;
In a more advanced case, we might have given each observer a reference to the weather
station object. This could allow the observer the ability to compare the state of the
subject in detail with its own state and make any necessary updates to its own state.
The strategy pattern is a behavioral object design pattern. In the strategy pattern, dif-
ferent algorithms are represented as Concrete Strategy classes, and they share a common
Strategy interface. A Context object contains a reference to a Strategy. By changing
the Context’s Strategy, different behaviors can be obtained. Although these behaviors
are different, the different strategies all operate on data from the Context.
The strategy pattern is one way that composition can be used as an alternative to sub-
classing. Rather than providing different behaviors via subclasses overriding methods
in superclasses, the strategy pattern allows different behaviors to be placed in Con-
crete Strategy classes which share the common Strategy interface. A Context class is
composed of a reference to a Strategy.
Here is an example of the strategy pattern. First, we’ll define a Strategy interface. It
declares a checkTemperature() method.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . s t r a t e g y ;
/� �
�
� @author b o n i f a c e
�/
public interface Strategy {
boolean c h e c k T e m p e r a t u r e ( i n t temperatureInF ) ;
The HikeStrategy class is a concrete strategy class that implements the Strategy in-
terface. The checkTemperature method is implemented so that if the temperature is
between 50 and 90, it returns true. Otherwise it returns false.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . s t r a t e g y ;
/� �
�
� @author b o n i f a c e
�/
public class HikeStrategy implements Strategy {
@Override
public boolean c h e c k T e m p e r a t u r e ( i n t t e m p e r a t u r e I n F ) {
i f ( ( t e m p e r a t u r e I n F >= 5 0 ) && ( t e m p e r a t u r e I n F <= 9 0 ) ) {
return true ;
} else {
return f a l s e ;
}
}
}
The SkiStrategy implements the Strategy interface. If the temperature is 32 or less, the
checkTemperature method returns true. Otherwise it returns false.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . s t r a t e g y ;
/� �
�
� @author b o n i f a c e
�/
public class SkiStrategy implements Strategy {
@Override
public boolean c h e c k T e m p e r a t u r e ( i n t temperatureInF ) {
i f ( t e m p e r a t u r e I n F <= 3 2 ) {
return true ;
} else {
return f a l s e ;
}
}
}
Design Patterns and Software Refactoring 118
The Context class contains a temperature and a reference to a Strategy. The Strategy
can be changed, resulting in different behavior that operates on the same data in the
Context. The result of this can be obtained from the Context via the getResult() method.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . s t r a t e g y ;
/� �
�
� @author b o n i f a c e
�/
public class Context {
int temperatureInF ;
Strategy strategy ;
public boolean g e t R e s u l t () {
return strategy . checkTemperature ( temperatureInF ) ;
}
}
The MainDriver class creates a Context object with a temperature of 60 and with a
SkiStrategy. It displays the temperature from the context and whether that temperature
is OK for skiing. After that, it sets the Strategy in the Context to HikeStrategy. It then
displays the temperature from the context and whether that temperature is OK for
hiking.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . s t r a t e g y ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
S t r a t e g y s k i S t r a t e g y = new S k i S t r a t e g y ( ) ;
C o n t e x t c o n t e x t = new C o n t e x t ( t e m p e r a t u r e I n F , skiStrategy ) ;
S t r a t e g y h i k e S t r a t e g y = new H i k e S t r a t e g y ( ) ;
context . setStrategy ( hikeStrategy ) ;
}
}
The command pattern is a behavioral object design pattern. In the command pattern,
a Command interface declares a method for executing a particular action. Concrete
Command classes implement the execute() method of the Command interface, and this
execute() method invokes the appropriate action method of a Receiver class that the
Concrete Command class contains. The Receiver class performs a particular action. A
Client class is responsible for creating a Concrete Command and setting the Receiver of
the Concrete Command. An Invoker class contains a reference to a Command and has
a method to execute the Command.
In the command pattern, the invoker is decoupled from the action performed by the
receiver. The invoker has no knowledge of the receiver. The invoker invokes a command,
and the command executes the appropriate action of the receiver. Thus, the invoker
can invoke commands without knowing the details of the action to be performed. In
addition, this decoupling means that changes to the receiver’s action don’t directly affect
the invocation of the action.
The command pattern can be used to perform ’undo’ functionality. In this case, the
Command interface should include an unexecute() method.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . c o m m a n d ;
/� �
�
� @author b o n i f a c e
�/
public interface Command {
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . c o m m a n d ;
/� �
�
� @author b o n i f a c e
�/
Design Patterns and Software Refactoring 120
Lunch lunch ;
@Override
public void e x e c u t e () {
lunch . makeLunch () ;
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . c o m m a n d ;
/� �
�
� @author b o n i f a c e
�/
public class DinnerCommand implements Command {
Dinner dinner ;
@Override
public void e x e c u t e () {
dinner . makeDinner () ;
}
}
Lunch is a receiver.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . c o m m a n d ;
/� �
�
� @author b o n i f a c e
�/
public class Lunch {
public void m a k e L u n c h () {
S y s t e m . o u t . p r i n t l n ( ” Lunch i s b e i n g made” ) ;
}
}
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . c o m m a n d ;
/� �
�
� @author b o n i f a c e
�/
public class Dinner {
public void m a k e D i n n e r () {
S y s t e m . o u t . p r i n t l n ( ” Dinner is b e i n g made” ) ;
}
}
MealInvoker is the invoker class. It contains a reference to the Command to invoke. Its
invoke() method calls the execute() method of the Command.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . c o m m a n d ;
/� �
�
� @author b o n i f a c e
Design Patterns and Software Refactoring 121
�/
public class MealInvoker {
Command command ;
public void i n v o k e () {
command . execute () ;
}
}
The MainDriver class demonstrates the command pattern. It instantiates a Lunch (re-
ceiver) object and creates a LunchCommand (concrete command) with the Lunch. The
LunchCommand is referenced by a Command interface reference. Next, we perform the
same procedure on the Dinner and DinnerCommand objects. After this, we create a
MealInvoker object with lunchCommand, and we call the invoke() method of mealIn-
voker. After this, we set mealInvoker’s command to dinnerCommand, and once again
call invoke() on mealInvoker.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . c o m m a n d ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
public s t a t i c void main ( S t r i n g [ ] args ) {
L u n c h l u n c h = new L u n c h ( ) ; // r e c e i v e r
C o m m a n d l u n c h C o m m a n d = new L u n c h C o m m a n d ( l u n c h ) ; // c o n c r e t e command
D i n n e r d i n n e r = new D i n n e r ( ) ; // r e c e i v e r
C o m m a n d d i n n e r C o m m a n d = new D i n n e r C o m m a n d ( d i n n e r ) ; // c o n c r e t e command
M e a l I n v o k e r m e a l I n v o k e r = new M e a l I n v o k e r ( l u n c h C o m m a n d ) ; // i n v o k e r
mealInvoker . invoke () ;
As you can see, the invoker invokes a command, but has no direct knowledge of the
action being performed by the receiver.
The state pattern is a behavioral object design pattern. The idea behind the state
pattern is for an object to change its behavior depending on its state. In the state
pattern, we have a Context class, and this class has a State reference to a Concrete State
instance. The State interface declares particular methods that represent the behaviors of
a particular state. Concrete States implement these behaviors. By changing a Context’s
Concrete State, we change its behavior. In essence, in the state pattern, a class (the
Context) is supposed to behave like different classes depending on its state. The state
pattern avoids the use of switch and if statements to change behavior.
Let’s look at an example of the state pattern. First off, we’ll define the EmotionalState
interface. It declares two methods, sayHello() and sayGoodbye().
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . s t a t e ;
/� �
�
� @author b o n i f a c e
�/
public interface EmotionalState {
The HappyState class is a Concrete State that implements sayHello() and sayGoodbye()
of EmotionalState. These messages are cheerful (representing a happy state).
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . s t a t e ;
/� �
�
� @author b o n i f a c e
�/
// C o n c r e t e S t a t e
public class HappyState implements EmotionalState {
@Override
public String sayGoodbye () {
r e t u r n ”Bye , f r i e n d ! ” ;
}
@Override
public String sayHello () {
return ” Hello , f r i e n d ! ” ;
}
The SadState class also implements the EmotionalState interface. The messages are sad
(representing a sad state).
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . s t a t e ;
/� �
�
� @author b o n i f a c e
�/
// C o n c r e t e S t a t e
public class SadState implements EmotionalState {
@Override
public String sayGoodbye () {
r e t u r n ” Bye . S n i f f , s n i f f . ” ;
}
@Override
public String sayHello () {
return ” Hello . Sniff , s n i f f . ” ;
}
}
Design Patterns and Software Refactoring 123
The Person class is the Context class. It contains an EmotionalState reference to a con-
crete state. In this example, we have Person implement the EmotionalState reference,
and we pass the calls to Person’s sayHello() and sayGoodbye() methods on to the corre-
sponding methods on the emotionalState reference. As a result of this, a Person object
behaves differently depending on the state of Person (ie, the current EmotionalState
reference).
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . s t a t e ;
/� �
�
� @author b o n i f a c e
�/
// C o n t e x t
public class Person implements EmotionalState {
EmotionalState emotionalState ;
@Override
public String sayGoodbye () {
return emotionalState . sayGoodbye () ;
}
@Override
public String sayHello () {
return emotionalState . sayHello () ;
}
}
The MainDriver class demonstrates the state pattern. First, it creates a Person object
with a HappyState object. We display the results of sayHello() and sayGoodbyte() when
the person object is in the happy state. Next, we change the person object’s state with
a SadState object. We display the results of sayHello() and sayGoodbyte(), and we see
that in the sad state, the person object’s behavior is different.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . s t a t e ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
public s t a t i c void main ( S t r i n g [ ] args ) {
P e r s o n p e r s o n = new P e r s o n ( new H a p p y S t a t e ( ) ) ;
S y s t e m . o u t . p r i n t l n ( ” H e l l o i n happy s t a t e : ” + p e r s o n . s a y H e l l o ( ) ) ;
S y s t e m . o u t . p r i n t l n ( ” Goodbye i n happy s t a t e : ” + p e r s o n . s a y G o o d b y e ( ) ) ;
p e r s o n . s e t E m o t i o n a l S t a t e ( new S a d S t a t e ( ) ) ;
S y s t e m . o u t . p r i n t l n ( ” H e l l o i n sad s t a t e : ” + p e r s o n . s a y H e l l o ( ) ) ;
S y s t e m . o u t . p r i n t l n ( ” Goodbye i n s a d s t a t e : ” + p e r s o n . s a y G o o d b y e ( ) ) ;
Note that we don’t necessarily need to have the Context (ie, Person) implement the
EmotionalState interface. The behavioral changes could have been internal to the Con-
text rather than exposing EmotionalState’s methods to the outside. However, having
the Context class implement the State interface allows us to directly access the different
behaviors that result from the different states of the Context.
Design Patterns and Software Refactoring 124
The visitor pattern is a behavioral object design pattern. The visitor pattern is used
to simplify operations on groupings of related objects. These operations are performed
by the visitor rather than by placing this code in the classes being visited. Since the
operations are performed by the visitor rather than by the classes being visited, the
operation code gets centralized in the visitor rather than being spread out across the
grouping of objects, thus leading to code maintainability. The visitor pattern also avoids
the use of the instanceof operator in order to perform calculations on similar classes.
In the visitor pattern, we have a Visitor interface that declares visit() methods for
the various types of elements that can be visited. Concrete Visitors implement the
Visitor interface’s visit() methods. The visit() methods are the operations that should
be performed by the visitor on an element being visited.
The related classes that will be visited implement an Element interface that declares
an accept() method that takes a visitor as an argument. Concrete Elements implement
the Element interface and implement the accept() method. In the accept() method, the
visitor’s visit() method is called with ’this’, the current object of the Concrete Element
type.
The elements to visit all implement the accept() method that takes a visitor as an
argument. In this method, they call the visitor’s visit() method with ’this’. As a result
of this, an element takes a visitor and then the visitor performs its operation on the
element.
Let’s illustrate the visitor pattern with an example. First, we’ll define a NumberVisitor
interface. This interface declares three visit methods which take different types as ar-
guments. Note that if we only wrote one visit method, we’d have to use the instanceof
operator or a similar technique to handle the different element types. However, since
Design Patterns and Software Refactoring 125
we have separate visit methods, we don’t need the instanceof operator, since each visit
method handles a different type.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . v i s i t o r ;
/� �
�
� @author b o n i f a c e
�/
public interface NumberVisitor {
All of the elements classes to be visited will implement the NumberElement interface.
This interface has a single method that takes a NumberVisitor as an argument
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . v i s i t o r ;
/� �
�
� @author b o n i f a c e
�/
public interface NumberElement {
Let’s create a TwoElement class that implements NumberElement. It has two int fields.
Its accept() method calls the visitor’s visit() method with ’this’. The operator to be
performed on TwoElement is performed by the visitor.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . v i s i t o r ;
/� �
�
� @author b o n i f a c e
�/
public class TwoElement implements NumberElement{
int a;
int b;
@Override
public void a c c e p t ( N u m b e r V i s i t o r visitor ) {
visitor . visit ( this ) ;
}
}
The ThreeElement class is similar to TwoElement, except that it has three int fields.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . v i s i t o r ;
/� �
�
� @author b o n i f a c e
�/
public class ThreeElement implements NumberElement {
int a;
int b;
int c;
this . c = c ;
}
@Override
public void a c c e p t ( N u m b e r V i s i t o r visitor ) {
visitor . visit ( this ) ;
}
}
Now, let’s create a visitor called SumVisitor that implements the NumberVisitor inter-
face. For TwoElement and ThreeElement objects, this visitor will sum up the int fields.
For a List of NumElements (ie, TwoElement and ThreeElement objects), this visitor
will iterate over the elements and call their accept() methods. As a result of this, the
visitor will perform visit operations on all the TwoElement and ThreeElement objects
that make up the list, since the call to accept() in turn calls the visitor’s visit methods
for the TwoElement and ThreeElement objects.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . v i s i t o r ;
/� �
�
� @author b o n i f a c e
�/
public class SumVisitor implements NumberVisitor {
@Override
public void vi sit ( T w o E l e m e n t t w o E l e m e n t ) {
int sum = twoElement . a + twoElement . b ;
S y s t e m . o u t . p r i n t l n ( t w o E l e m e n t . a + ”+” + t w o E l e m e n t . b + ”=” + s u m ) ;
}
@Override
public void vi sit ( T h r e e E l e m e n t t h r e e E l e m e n t ) {
int sum = threeElement . a + threeElement . b + threeElement . c ;
S y s t e m . o u t . p r i n t l n ( t h r e e E l e m e n t . a + ”+” + t h r e e E l e m e n t . b + ”+” + t h r e e E l e m e n t . c + ”=←�
” + sum ) ;
}
@Override
p u b l i c v o i d v i s i t ( L i s t <N u m b e r E l e m e n t > e l e m e n t L i s t ) {
f o r ( N u m b e r E l e m e n t ne : e l e m e n t L i s t ) {
ne . accept ( t h i s ) ;
}
}
}
Here is another visitor, TotalSumVisitor. In addition to summing up the int fields and
displaying the sum, this visitor will keep track of the total sums of all the elements that
are visited.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . v i s i t o r ;
/� �
�
� @author b o n i f a c e
�/
public class TotalSumVisitor implements NumberVisitor {
int totalSum = 0;
@Override
public void vi sit ( T w o E l e m e n t t w o E l e m e n t ) {
int sum = twoElement . a + twoElement . b ;
S y s t e m . o u t . p r i n t l n ( ” Adding ” + t w o E l e m e n t . a + ”+” + t w o E l e m e n t . b + ”=” + s u m + ” t o ←�
total ”) ;
t o t a l S u m += s u m ;
}
@Override
public void vi sit ( T h r e e E l e m e n t t h r e e E l e m e n t ) {
int sum = threeElement . a + threeElement . b + threeElement . c ;
S y s t e m . o u t . p r i n t l n ( ” Adding ” + t h r e e E l e m e n t . a + ”+” + t h r e e E l e m e n t . b + ”+” + ←�
t h r e e E l e m e n t . c + ”=” + s u m
+ ” to t o t a l ” ) ;
Design Patterns and Software Refactoring 127
t o t a l S u m += s u m ;
}
@Override
p u b l i c v o i d v i s i t ( L i s t <N u m b e r E l e m e n t > e l e m e n t L i s t ) {
f o r ( N u m b e r E l e m e n t ne : e l e m e n t L i s t ) {
ne . accept ( t h i s ) ;
}
}
Let’s see the visitor pattern in action. The MainDriver class creates two TwoElement
objects and one ThreeElement object. It creates a list of NumberElements and adds the
TwoElement object and the ThreeElement object to the list. Next, we create a SumVis-
itor and we visit the list with the SumVisitor. After this, we create a TotalSumVisitor
and visit the list with the TotalSumVisitor. We display the total sum via the call to
TotalSumVisitor’s getTotalSum() method.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . v i s i t o r ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
public s t a t i c void main ( S t r i n g [ ] args ) {
T w o E l e m e n t t w o 1 = new T w o E l e m e n t ( 3 , 3 ) ;
T w o E l e m e n t t w o 2 = new T w o E l e m e n t ( 2 , 7 ) ;
T h r e e E l e m e n t t h r e e 1 = new T h r e e E l e m e n t ( 3 , 4 , 5) ;
Notice that if we’d like to perform new operations on the grouping of elements, all we
would need to do is write a new visitor class. We would not have to make any additions
to the existing element classes, since they provide the data but none of the code for the
operations.
Design Patterns and Software Refactoring 128
The iterator pattern is a behavioral object design pattern. The iterator pattern allows for
the traversal through the elements in a grouping of objects via a standardized interface.
An Iterator interface defines the actions that can be performed. These actions include
being able to traverse the objects and also obtain the objects.
Java features the widely used [Link] interface which is used to iterate through
things such as Java collections. We can write our own iterator by implementing [Link].
This interface features the hasNext(), next(), and remove() methods. When writing an
iterator for a class, it is very common for the iterator class to be an inner class of the
class that we’d like to iterate through.
Let’s look at an example of this. We have an Item class, which represents an item on a
menu. An item has a name and a price.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . i t e r a t o r ;
/� �
�
� @author b o n i f a c e
�/
public class Item {
String name ;
float price ;
Here is the Menu class. It has a list of menu items of type Item. Items can be added via
the addItem() method. The iterator() method returns an iterator of menu items. The
MenuIterator class is an inner class of Menu that implements the Iterator interface for
Item objects. It contains basic implementations of the hasNext(), next(), and remove()
methods.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . i t e r a t o r ;
Design Patterns and Software Refactoring 129
/� �
�
� @author b o n i f a c e
�/
public class Menu {
L i s t <I t e m > m e n u I t e m s ;
public Menu () {
m e n u I t e m s = new A r r a y L i s t <I t e m >() ;
}
p u b l i c I t e r a t o r <I t e m > i t e r a t o r ( ) {
r e t u r n new M e n u I t e r a t o r ( ) ;
}
@Override
public boolean h a s N e x t () {
i f ( c u r r e n t I n d e x >= m e n u I t e m s . s i z e ( ) ) {
return f a l s e ;
} else {
return true ;
}
}
@Override
public Item next () {
r e t u r n m e n u I t e m s . g e t ( c u r r e n t I n d e x ++) ;
}
@Override
public void r e m o v e () {
m e n u I t e m s . r e m o v e (−− c u r r e n t I n d e x ) ;
}
The MainDriver class demonstrates the iterator pattern. It creates three items and
adds them to the menu object. Next, it gets an Item iterator from the menu object and
iterates over the items in the menu. After this, it calls remove() to remove the last item
obtained by the iterator. Following this, it gets a new iterator object from the menu
and once again iterates over the menu items.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . i t e r a t o r ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
Item i 1 = new I t e m ( ” s p a g h e t t i ” , 7 . 5 0 f ) ;
Item i 2 = new I t e m ( ” hamburger ” , 6 . 0 0 f ) ;
Item i 3 = new I t e m ( ” c h i c k e n s a n d w i c h ” , 6 . 5 0 f ) ;
M e n u m e n u = new M e n u ( ) ;
menu . a d d I t e m ( i1 ) ;
menu . a d d I t e m ( i2 ) ;
menu . a d d I t e m ( i3 ) ;
S y s t e m . o u t . p r i n t l n ( ” D i s p l a y i n g Menu : ” ) ;
I t e r a t o r <I t e m > i t e r a t o r = m e n u . i t e r a t o r ( ) ;
while ( iterator . hasNext () ) {
Item item = iterator . next () ;
System . out . println ( item ) ;
}
S y s t e m . o u t . p r i n t l n ( ” \ nRemoving l a s t item r e t u r n e d ” ) ;
iterator . remove () ;
S y s t e m . o u t . p r i n t l n ( ” \ n D i s p l a y i n g Menu : ” ) ;
Design Patterns and Software Refactoring 130
}
}
Note that since the menu utilizes a Java collection, we could have used an iterator
obtained for the menu list rather than write our own iterator as an inner class.
The memento pattern is a behavioral design pattern. The memento pattern is used to
store an object’s state so that this state can be restored at a later point. The saved
state data in the memento object is not accessible outside of the object to be saved and
restored. This protects the integrity of the saved state data.
In this pattern, an Originator class represents the object whose state we would like
to save. A Memento class represents an object to store the state of the Originator.
The Memento class is typically a private inner class of the Originator. As a result,
the Originator has access to the fields of the memento, but outside classes do not have
access to these fields. This means that state information can be transferred between
the Memento and the Originator within the Originator class, but outside classes do not
have access to the state data stored in the Memento.
The memento pattern also utilizes a Caretaker class. This is the object that is responsible
for storing and restoring the Originator’s state via a Memento object. Since the Memento
is a private inner class, the Memento class type is not visible to the Caretaker. As a
result, the Memento object needs to be stored as an Object within the Caretaker.
Now, let’s look at an example. The DietInfo class is our Originator class. We’d like to
be able to save and restore its state. It contains 3 fields: a dieter name field, the day
number of the diet, and the weight of the dieter on the specified day of the diet.
This class contains a private inner class called Memento. This is our Memento class that
is used to save the state of DietInfo. Memento has 3 fields representing the dieter name,
the day number, and the weight of the dieter.
Design Patterns and Software Refactoring 131
Notice the save() method of DietInfo. This creates and returns a Memento object. This
returned Memento object gets stored by the caretaker. Note that [Link] is
not visible, so the caretaker can’t reference [Link]. Instead, it stores the
reference as an Object.
The restore() method of DietInfo is used to restore the state of the DietInfo. The
caretaker passes in the Memento (as an Object). The memento is cast to a Memento
object and then the DietInfo object’s state is restored by copying over the values from
the memento.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . m e m e n t o ;
/� �
�
� @author b o n i f a c e
�/
// o r i g i n a t o r − o b j e c t whose s t a t e we want t o s a v e
public class DietInfo {
String personName ;
int dayNumber ;
int weight ;
public void r e s t o r e ( O b j e c t o b j M e m e n t o ) {
Memento memento = ( Memento ) objMemento ;
personName = memento . mementoPersonName ;
dayNumber = memento . mementoDayNumber ;
weight = memento . mementoWeight ;
}
DietInfoCaretaker is the caretaker class that is used to store the state (ie, the memento)
of a DietInfo object (ie, the originator). The memento is stored as an object since
[Link] is not visible to the caretaker. This protects the integrity of the data
stored in the Memento object. The caretaker’s saveState() method saves the state of the
DietInfo object. The caretaker’s restoreState() method restores the state of the DietInfo
object.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . m e m e n t o ;
/� �
�
� @author b o n i f a c e
�/
// c a r e t a k e r − s a v e s and r e s t o r e s a D i e t I n f o object � s s t a t e v i a a memento
Design Patterns and Software Refactoring 132
Object objMemento ;
public void s a v e S t a t e ( D i e t I n f o d i e t I n f o ) {
objMemento = dietInfo . save () ;
}
The MainDriver class demonstrates the memento pattern. It creates a caretaker and then
a DietInfo object. The DietInfo object’s state is changed and displayed. At one point,
the caretaker saves the state of the DietInfo object. After this, the DietInfo object’s
state is further changed and displayed. After this, the caretaker restores the state of the
DietInfo object. We verify this restoration by displaying the DietInfo object’s state.
package za . ac . c p u t . k a b a s o b . d e s i g n p a t t e r n s . b e h a v i o r a l . m e m e n t o ;
/� �
�
� @author b o n i f a c e
�/
public class MainDriver {
// c a r e t a k e r
DietInfoCaretaker d i e t I n f o C a r e t a k e r = new D i e t I n f o C a r e t a k e r ( ) ;
// o r i g i n a t o r
D i e t I n f o d i e t I n f o = new D i e t I n f o ( ” Fred ” , 1 , 1 0 0 ) ;
System . out . println ( dietInfo ) ;
S y s t e m . out . p r i n t l n ( ” Saving s t a t e . ” ) ;
dietInfoCaretaker . saveState ( dietInfo ) ;
}
}
Notice how the state changes, and how we are able to save and restore the state of the
originator via the caretaker’s reference to the memento.
Part 1
The First part requires you to read and master 6 design patterns, two from each category.
Write a small write up on the practical usage of the patterns you have chosen. Your
solution should follow the pattern below.
� Creational
� Structural
� Behavioural
4. Collaborations
5. Consequences
6. Implementation
7. Sample Code
8. Known Uses
9. Related Patterns
Part 2
Re-Write the Design Patterns in Section, but use JUnit Tests in place of the Driver class
used in the examples. Also write code to demostrate the usage of the Interpreter Design
Pattern.