Step 5 - DesignPatterns - Complete
Step 5 - DesignPatterns - Complete
About Author
He has extensive experience in ecommerce and EAI domain using J2EE based products like Hybris, ATG,
OFBiz, WCS, WebMethods and Jitterbit. He is currently working with HCL Technology in Multi Channel
Commerce Retail Center of Excellence (MCC Retail COE) domain as a java architect.
He also holds PG diploma in operations and also Sun, RUP (Rational Unified Process) and webMethods
certified.
· Person who is confused after reading n number of materials over internet and looking for a concise
and concrete one.
What is a Pattern?
q Each pattern is a three-part rule, which expresses a relation between a certain context, a problem
and a solution.
q Hence, the common definition of a pattern: “A solution to a problem in a context.”
q Patterns can be applied to many different areas of human endeavor, including software
development.
q The Design Patterns are description of communicating objects and classes that are customized to
solve a general design problem in a particular context.
q A design pattern names, abstracts, and identifies the key aspects of the common design structure
that make it useful for creating a reusable object oriented design.
q The design pattern identifies the participating classes and instances, their roles and collaborations,
and the distribution of responsibilities.
q Each design pattern focuses on a particular object-oriented design problem or issue. It describes
when it applies, whether it can be applied in view of other design constraints, and the consequences
and trade-offs of its use.
Life without it - like constructing your dream house without any layout and realizing the problems in
middle or after construction.
Life with it – now you have a layout on which you worked a lot before actual construction, e.g. proper
spaces for ventilation, future expansion, vastu compliant, parking, entertaining guests, security systems and
many more.
The whole idea behind design patterns is to develop a standardized way to represent general solutions to
commonly encountered problems in software development.
q Class Patterns- Focus on the relationships between classes and their subclasses and involve
inheritance reuse
q Object Patterns- Focus on the relationships between objects and involve composition reuse
Design Patterns
*Bold ones are most commonly used patterns that you will come across in your day to day programming.
So, what’s the great stuff? Well, that’s true. The new Operator creates the instance of an object, but this is
hard-coding. Creating good software is difficult and so, hard coding is the last thing one should do. Also, at
times the very nature of the object, which is created, can change according to the nature of the program. In
such scenarios, we can make use of patterns to give this a more general and flexible approach.
1. Singleton Pattern
2. Factory Pattern
3. Abstract Factory Pattern
4. Builder Pattern
5. Prototype Pattern
1. Singleton pattern
In software engineering, the singleton design pattern is used to restrict instantiation of a class to one
object. This is useful when exactly one object is needed to coordinate actions across the system.
Sometimes it is generalized to systems that operate more efficiently when only one or a few objects exist.
It is also considered an anti-pattern since it is often used as a euphemism for global variable. Before
designing a class as a singleton, it is wise to consider whether it would be enough to design a normal class
and just use one instance.
The singleton pattern is implemented by creating a class with a method that creates a new instance of the
object if one does not exist. If an instance already exists, it simply returns a reference to that object. To
make sure that the object cannot be instantiated any other way, the constructor is made either private or
protected. Note the distinction between a simple static instance of a class and a singleton. Although a
singleton can be implemented as a static instance, it can also be lazily constructed, requiring no memory or
resources until needed.
The singleton pattern must be carefully constructed in multi-threaded applications. If two threads are to
execute the creation method at the same time when a singleton does not yet exist, they both must check for
an instance of the singleton and then only one should create the new one. If the programming language has
concurrent processing capabilities the method should be constructed to execute as a mutually exclusive
operation.
The classic solution to this problem is to use mutual exclusion on the class that indicates that the object is
being instantiated.
package example.creational.singleton;
return obj;
}
}
Note – Now there will be one object in whole JVM, no one can create multiple instances in the same JVM.
We should not mark them Serializable and Cloneable also.
Product Creator
product = factoryMethod()
factoryMethod()
ConcreteCreator
ConcreteProduct
factoryMethod() return new ConcreteProduct()
Participants
q Product – Defines the interface of objects the factory method creates.
q ConcreteProduct – Implements the product interface.
q Creator – Declares the factory method, which returns an object of type Product. Creator may also
define a default implementation of the factory method that returns a default ConcreteProduct
object.
q ConcreteCreator – Overrides the factory method to return an instance of a ConcreteProduct.
In this figure, x is a base class and classes xy and xz are derived from it. The Factory is a class that decides
which of these subclasses to return depending on the arguments you give it. On the right, we define a
getClass() method to be one that passes in some value abc, and that returns some instance of the class x.
Which one it returns doesn't matter to the programmer since they all have the same methods, but different
Example: Let’s suppose an application asks for entering the name and sex of a person. If the sex is Male
(M), it displays welcome message saying Hello Mr. <Name> and if the sex is Female (F), it displays
message saying Hello Ms <Name>.
package example.creational.factory;
This is a simple class Person having methods for name and gender. Now, we will have two sub-classes,
Male and Female which will print the welcome message on the screen.
package example.creational.factory;
Now, we have to create a client, or a SalutationFactory which will return the welcome message depending
on the data provided.
This class accepts two arguments from the system at runtime and prints the names.
A software design pattern, the Abstract Factory Pattern provides a way to encapsulate a group of
individual factories that have a common theme. In normal usage, the client software would create a
concrete implementation of the abstract factory and then use the generic interfaces to create the concrete
objects that are part of the theme. The client does not know (nor care) about which concrete objects it gets
from each of these internal factories since it uses only the generic interfaces of their products. This pattern
separates the details of implementation of a set of objects from its general usage.
In software development, a Factory is the location in the code at which objects are constructed. The intent
in employing the pattern is to insulate the creation of objects from their usage. This allows for new derived
types to be introduced with no change to the code that uses the base object.
Use of this pattern makes it possible to interchange concrete classes without changing the code that uses
them, even at runtime. However, employment of this pattern, as with similar design patterns, incurs the
risk of unnecessary complexity and extra work in the initial writing of code.
Application: Suppose you have the task of building a user interface framework that works on top of
multiple windowing systems, like MS-Windows, Motif, or Mac OS. It must work on each platform with
the platform's native look and feel. You organize it by creating an abstract class for each type of widget
(text field, push button, list box, etc.) and then writing a concrete subclass of each of those classes for each
supported platform. To make this robust, you need to ensure that the widget objects created are all for the
desired platform. That is where the abstract factory comes into play.
An abstract factory class defines methods to create an instance of each abstract class that represents a user
interface widget. Concrete factories are concrete subclasses of an abstract factory that implements its
methods to create instances of concrete widget classes for the same platform.
Participants
q Client -Classes in the Client role use various widget classes to request or receive services from the
product that the client is working with. Client classes only know about the abstract widget classes.
They should have no knowledge of any concrete widget classes.
q AbstractFactory - AbstractFactory classes define abstract methods for creating instances of
concrete widget classes. Abstract factory classes have a static method shown in the above diagram
as getFactory. Another common name for that method is getToolkit. A Client object calls that
method to get an instance of a concrete factory appropriate for working with a particular product.
q ConcreteFactory1, ConcreteFactory2 - Classes in this role implement the methods defined by
their abstract factory superclasses to create instances of concrete widget classes. Client classes that
call these methods should not have any direct knowledge of these concrete factory classes, but
instead access singleton instances of these classes by calling a method of their abstract factory
superclass.
q WidgetA, WidgetB - Interfaces in this role correspond to a feature of a product. Classes that
implement an interface in this role work with the product to which the interface corresponds.
q Product1WidgetA, Product2WidgetA - Classes in this role are concrete classes that correspond
to a feature of a product that they work with. You can generically refer to classes in this role as
concrete widgets.
10 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Example:
/* GUIFactory example */
package example.creational.absfac;
public abstract class GUIFactory {
public static GUIFactory getFactory() {
int sys = readFromConfigFile("OS_TYPE");
if (sys == 0) {
return (new WinFactory());
} else {
return (new OSXFactory());
}
}
package example.creational.absfac;
class WinFactory extends GUIFactory {
public Button createButton() {
return (new WinButton());
}
}
package example.creational.absfac;
class OSXFactory extends GUIFactory {
public Button createButton() {
return (new OSXButton());
}
}
package example.creational.absfac;
public abstract class Button {
package example.creational.absfac;
11 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
package example.creational.absfac;
class OSXButton extends Button {
public void paint() {
System.out.println("I'm a OSXButton: " + getCaption());
}
}
package example.creational.absfac;
public class Application {
public static void main(String[] args) {
GUIFactory aFactory = GUIFactory.getFactory();
Button aButton = aFactory.createButton();
aButton.setCaption("Play");
aButton.paint();
}
}
12 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
4. Builder pattern
Builder is used to separate the construction of complex objects from their representation so the
construction process can be used to create different representations. The construction logic is isolated from
the actual steps used to create the complex object and, therefore, the construction process can be reused to
create different complex objects from the same set of simple objects. This tends to reduce the size of
classes by factoring out methods that are responsible for constructing complex objects into a single class
(called a Director) that is responsible for knowing how to build complex objects. In addition, Builder can
be used when you want to create objects in a step-wise manner depending on parameters you acquire along
the way.
The class diagram shown in the next figure shows the client instantiates the Builder and Director classes.
The Builder represents the complex object in terms of simpler objects and primitive types. The client then
passes the Builder object, as a parameter, to the Director's constructor, which is responsible for calling the
appropriate Builder methods. An abstract AbstractBuilder class is created to provide the Director with a
uniform interface for all concrete Builder classes. Thus, you can add new types of complex objects by
defining only the structure (Builder) and reuse the logic for the actual construction process (Director). Only
the client needs to know about the new types. The Director simply needs to know which Builder methods
to call.
Builder, as the name suggests builds complex objects from simple ones step-by-step. It separates the
construction of complex objects from their representation.
Participants
q Builder - Abstract interface for creating products.
q Concrete Builder - Provides implementation for Builder and constructs and assembles parts to
build the products.
q Director - Construct an object using the Builder pattern.
q Product - The complex object under construction
13 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Example:
/** "Product" */
package example.creational.builder;
public class Pizza {
private String dough = "";
private String sauce = "";
private String topping = "";
14 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
/** "ConcreteBuilder" */
package example.creational.builder;
class SpicyPizzaBuilder extends PizzaBuilder {
public void buildDough() {
pizza.setDough("pan baked");
}
/** "Director" */
package example.creational.builder;
class Waiter {
private PizzaBuilder pizzaBuilder;
class BuilderExample {
public static void main(String[] args) {
Waiter waiter = new Waiter();
PizzaBuilder hawaiian_pizzabuilder = new HawaiianPizzaBuilder();
PizzaBuilder spicy_pizzabuilder = new SpicyPizzaBuilder();
waiter.setPizzaBuilder(hawaiian_pizzabuilder);
waiter.constructPizza();
Pizza pizza = waiter.getPizza();
}
}
15 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
5. Prototype Pattern
The prototype means making a clone. This implies cloning of an object to avoid creation. If the cost of
creating a new object is large and creation is resource intensive, we clone the object. We use the interface
Cloneable and call its method clone() to clone the object.
It assumes that an initialized and instantiated class is available and clones it to make new instances rather
than creating new instances.
When we are not in a position to call a constructor for an object directly, we could alternatively clone a
pre-existing object (a prototype) of the same class.
Structure: The class diagram of this design pattern is as shown below:
Participants
q Prototype - Declares an interface for cloning itself.
q Concrete Prototypes – Implement an operation for cloning itself.
q Client – Creates a new object by asking a prototype to clone itself.
Example: Version-1 which uses method myClone() of prototype class SwimData. The method’s
implementation is provided by the concrete prototype class TimeSwimData.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public SwimInfo() {
super("Prototype example");
sdata = new TimeSwimData("swimmers.txt");
setGUI();
loadswList();
}
16 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
// -----------------------------------
public void actionPerformed(ActionEvent e) {
Object obj = e.getSource();
if (obj == Clone)
try {
cloneAndLoad();
} catch (CloneNotSupportedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (obj == Refresh)
loadswList();
if (obj == Quit)
System.exit(0);
}
// -----------------------------------
private void cloneAndLoad() throws CloneNotSupportedException {
// sxdata = sdata.myClone(); //deep cloning
sxdata = (SwimData) sdata.cloneMe(); // shallow cloning
sxdata.sort();
cloneList.removeAll();
// now print out sorted values from clone
for (int i = 0; i < sxdata.size(); i++) {
sw = sxdata.getSwimmer(i);
cloneList.add(sw.getName() + " " + sw.getTime());
}
}
// -----------------------------------
private void loadswList() {
swList.removeAll();
for (int i = 0; i < sdata.size(); i++) {
sw = sdata.getSwimmer(i);
swList.add(sw.getName() + " " + sw.getTime());
}
}
// -----------------------------------
17 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Panel p3 = new Panel();
cp.add(p3);
p3.add(Quit);
Clone.addActionListener(this);
Refresh.addActionListener(this);
Quit.addActionListener(this);
setBounds(100, 100, 500, 400);
setVisible(true);
}
// -----------------------------------
static public void main(String argv[]) {
new SwimInfo();
}
}
//Prototype Class: SwimData
package example.creational.prototype;
import java.io.*;
import java.util.*;
18 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//InputFile: Class for Reading Swimmers’ data from text file (Swimmers.txt)
package example.creational.prototype;
import java.awt.*;
import java.io.*;
// -----------------------------------------
public boolean checkErr() {
return errflag;
}
// -----------------------------------------
public String read() {
// read a single field up to a comma or end of line
String ret = "";
if (s == null) // if no data in string
{
s = readLine(); // read next line
}
if (s != null) // if there is data
{
s.trim(); // trim off blanks
int i = s.indexOf(","); // find next comma
if (i <= 0) {
ret = s.trim(); // if no commas go to end of line
s = null; // and null out stored string
} else {
ret = s.substring(0, i).trim(); // return left of comma
s = s.substring(i + 1); // save right of comma
}
} else
ret = null;
return ret; // return string
}
// -----------------------------------------
public String readLine() {
// read in a line from the file
s = null;
try {
s = f.readLine(); // could throw error
} catch (IOException e) {
19 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
errflag = true;
System.out.println("File read error");
}
return s;
}
// -----------------------------------------
public void close() {
try {
f.close(); // close file
} catch (IOException e) {
System.out.println("File close error");
errflag = true;
}
}
// -----------------------------------------
}
import java.util.*;
import java.io.*;
20 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
while (s != null) {
swimmers.add(new Swimmer(s));
s = f.readLine();
}
f.close();
}
// -------------------------------------------
public TimeSwimData(ArrayList sw) {
// this constructor copies vector as clone
swimmers = new ArrayList();
for (int i = 0; i < sw.size(); i++) {
swimmers.add(sw.get(i));
}
}
// -------------------------------------------
public SwimData myClone() {
return new TimeSwimData(swimmers);
}
// -------------------------------------------
public int size() {
return swimmers.size();
}
// -------------------------------------------
public String getName(int i) {
Swimmer sw = getSwimmer(i);
if (sw != null)
return sw.getName();
else
return "";
}
// -------------------------------------------
public Swimmer getSwimmer(int i) {
Swimmer sw;
if ((i >= 0) && (i < swimmers.size())) {
sw = (Swimmer) swimmers.get(i);
return sw;
} else
return null;
}
// -------------------------------------------
public void sort() {
Swimmer sw;
int i, j;
int max = swimmers.size();
Swimmer sd[] = new Swimmer[max];
for (i = 0; i < max; i++)
sd[i] = (Swimmer) swimmers.get(i);
for (i = 0; i < max; i++) {
for (j = i; j < max; j++) {
if (sd[i].getTime() > sd[j].getTime()) {
sw = sd[i];
sd[i] = sd[j];
sd[j] = sw;
21 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
}
}
}
swimmers.removeAll(swimmers);
for (i = 0; i < max; i++)
swimmers.add(sd[i]);
}
}
In the original class, the names are sorted by sex and then by time, while in the cloned class, they are
sorted only by time. In the figure below, we see the simple user interface that allows us to display the
original data on the left and the sorted data in the cloned class on the right:
The left-hand list box is loaded when the program starts and the right-hand list box is loaded when you click on the
Clone button. Now, let’s click on the Refresh button to reload the left-hand list box from the original data.
Why have the names in the left-hand list box also been re-sorted? This occurs in Java because the clone
method provides a shallow copy of the original object. In other words, the references to the data objects are
copies, but they refer to the same underlying data. Thus, any operation we perform on the copied data will
also occur on the original data in the Prototype class.
In some cases, this shallow copy may be acceptable, but if you want to make a deep copy of the data, there
is a clever trick using the serializable interface. A class is said to be serializable if you can write it out as a
stream of bytes and read those bytes back in to reconstruct the class. This is how Java remote method
22 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
invocation (RMI) is implemented. However, if we declare both the Swimmer and SwimData classes as
Serializable, we can write the bytes to an output stream and reread them to create a
complete data copy of that instance of a class.
Example: Version-2 which uses method cloneMe() of prototype class SwimData. This
method makes use of the clone() method of the Object class for shallow cloning. The
SwimData class also provides method deepClone() for deep cloning. Only modified part
of the classes in the previous example is reproduced here.
//InputFile: No Change
23 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//Concrete Prototype Class: TimeSwimData
Example: Version-3 is almost same as Version-2. The only change is that the method
cloneAndLoad() makes use of the method deepClone() of the SwimData class for deep
cloning.
//Swimmer: No Change
//InputFile: No Change
//Concrete Prototype Class: TimeSwimData (No Change)
24 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Structural Patterns
Structural patterns describe how classes and objects can be combined to form larger structures. The
difference between class patterns and object patterns is that class patterns describe how inheritance can be
used to provide more useful program interfaces. Object patterns, on the other hand, describe how objects
can be composed into larger structures using object composition, or the inclusion of objects within other
objects.
1. Adapter Pattern
2. Bridge Pattern
3. Composite Pattern
4. Decorator Pattern
5. Facade Pattern
6. Flyweight Pattern
7. Proxy Pattern
1. Adapter Pattern
The Adapter pattern is used to convert the programming interface of one class into that of another. We use
adapters whenever we want unrelated classes to work together in a single program. The concept of an
adapter is thus pretty simple; “Adapter pattern can let two incompatible systems communicate”
25 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Our job - design a class that will establish communication between two different types or we can say that
will bridge the gap among two.
//PetToWild.java
public class PetToWild implements WildAnimal{
PetAnimal pet;
public PetToWild(PetAnimal pet){
this.pet = pet;
}
public void roar(){
pet.speek();
}
public void run(){
for(int i=0;i<5;i++)
pet.walk();
}
}
//Test.java
class Test{
public static void main(String s[]){
Lion l = new Lion();
Cat c = new Cat();
WildAnimal petToWild = new PetToWild( c);
testWild(l);
testWild(petToWild);
}
static void testWild(WildAnimal wild){
wild.roar();
wild.run();
}
}
Participants
q Target – Defines the domain specific language that Client uses.
q Client – Collaborates with objects conforming to the Target interface.
q Adaptee – Defines an existing interface that needs adapting.
q Adapter – Adapts the interface of adaptee to the target interface.
26 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
2. Bridge Pattern
The bridge pattern is a design pattern used in software engineering which is meant to "decouple an
abstraction from its implementation so that the two can vary independently" (Gamma et. al.).
Participants
q Abstraction – Defines the abstraction's interface; maintains a reference to the Implementor and
forwards request to the Impementor.
q RefinedAbstraction – Extends the interface defined by the abstraction.
q Implementor – Defines the interface for implementation classes. This interface does not have to
correspond exactly to Abstraction’s interface; in fact the two interfaces can be quite different.
Typically the Implementor interface provides only primitive operations, and Abstraction defines
higher-level operations based on these primitives.
q ConcreteImplementor – Implements the Implementor interface and defines its concrete
implementation.
Example:
This example divides complex behavior among two categories - the abstraction and the implementation.
Implementation provided by -
The OrderedListImpl class provides the underlying storage capability for the list, and can be flexibly
paired with either of the classes which provide the abstraction.
27 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//Implementation
package example.structural.bridge;
interface ListImpl {
public void addItem(String item);
import java.util.ArrayList;
28 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//Abstraction
package example.structural.bridge;
class BaseList {
protected ListImpl implementor;
//Client
29 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
package example.structural.bridge;
listOne.add("One");
listOne.add("Two");
listOne.add("Three");
listOne.add("Four");
}
}
}
Output:
30 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
3. Composite Pattern
Frequently programmers develop systems in which a component may be an individual object or it may
represent a collection of objects. The Composite pattern is designed to accommodate both cases. You can
use the Composite to build part-whole hierarchies or to construct data representations of trees. In summary,
a composite is a collection of objects, any one of which may be either a composite, or just a primitive
object. In tree nomenclature, some objects may be nodes with additional branches and some may be leaves.
The problem that develops is the dichotomy between having a single, simple interface to access all the
objects in a composite, and the ability to distinguish between nodes and leaves. Nodes have children and
can have children added to them, while leaves do not at the moment have children, and in some
implementations may be prevented from having children added to them.
Participants
q Component - Declares the interface for objects in composition; implements default behaviour for
the interface common to all classes, as appropriate; declares an interface for accessing and
managing its child components.
q Leaf - Represents leaf objects in the composition and defines behaviour for primitive objects in the
composition.
q Composite - Defines behaviour for components having children; stores child components and
implements child-related operations in the Component interface.
q Client - manipulates objects in the composition through the Component interface.
31 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
// Component
package example.structure.composite;
import java.util.ArrayList;
interface Component {
public String defaultMethod();
//Composite
package example.structure.composite;
import java.util.ArrayList;
32 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//Leaf
package example.structure.composite;
import java.util.ArrayList;
class CompositePattern {
public static void main(String[] args) {
Composite england = new Composite("England");
Leaf york = new Leaf("York");
Leaf london = new Leaf("London");
england.addComponent(york);
england.addComponent(london);
england.removeComponent(york);
Composite france = new Composite("France");
france.addComponent(new Leaf("Paris"));
Composite europe = new Composite("Europe");
europe.addComponent(england);
europe.addComponent(france);
System.out.println(europe.defaultMethod());
}
}
The output is: (Europe: (England: London) (France: Paris))
33 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
4. Decorator Pattern
The Decorator Pattern is used for adding additional functionality to a particular object as opposed to a class
of objects. It is easy to add functionality to an entire class of objects by sub-classing an object, but it is
impossible to extend a single object this way. With the Decorator Pattern, you can add functionality to a
single object and leave others like it unmodified.
A Decorator, also known as a Wrapper, is an object that has an interface identical to an object that it
contains. Any calls that the decorator gets, it relays to the object that it contains, and adds its own
functionality along the way, either before or after the call. This gives you a lot of flexibility, since you can
change what the decorator does at runtime, as opposed to having the change be static and determined at
compile time by sub-classing. Since a Decorator complies with the interface that the object that it contains,
the Decorator is indistinguishable from the object that it contains. That is, a Decorator is a
concrete instance of the abstract class, and thus is indistinguishable from any other concrete instance,
including other decorators. This can be used to great advantage, as you can recursively nest decorators
without any other objects being able to tell the difference, allowing a near infinite amount of
customization.
Participants
q Component – Defines the interface for objects that can have responsibilities added to them
dynamically.
q ConcreteComponent - Defines an object to which additional responsibilities can be attached.
q Decorator – Maintains a reference to a Component object and defines an interface that conforms to
component’s interface.
q ConcreteDecorator – Adds responsibilities to the component.
34 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Example 1:
// the Window interface (Component )
package example.structure.decorator.ex1;
public interface Window {
public void draw(); // draws the Window
The following classes contain the decorators for all Window classes, including the decorator classes
themselves.
35 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
// the second Concrete Decorator which adds horizontal scrollbar functionality
package example.structure.decorator.ex1;
Here's a test program that creates a Window instance which is fully decorated (i.e., with vertical and
horizontal scrollbars), and prints its description:
package example.structure.decorator.ex1;
The output of this program is "simple window, including vertical scrollbars, including horizontal
scrollbars".
Notice how the getDescription method of the two decorators first retrieve the decorated Window's
description and "decorates" it with a suffix.
36 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Example 2: The JComponent class (abstract class) is assumed to be the Component class and JLabel
class is assumed to be the ConcreteComponent class.
//Client
package example.structure.decorator.ex2;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public DecoWindow() {
super("Deco Button");
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
JPanel jp = new JPanel();
getContentPane().add(jp);
jp.add(new CoolDecorator(new JButton("Cbutton")));
jp.add(new SlashDecorator(new CoolDecorator(new JButton("Dbutton"))));
jp.add(Quit = new JButton("Quit"));
Quit.addActionListener(this);
setSize(new Dimension(200, 100));
setVisible(true);
Quit.requestFocus();
}
import java.awt.BorderLayout;
import javax.swing.JComponent;
37 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//Concrete Decorator 1
package example.structure.decorator.ex2;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
38 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Example 3 –
TODO - You have used java IO package several times. But this time we want to create a stream
class that will convert all uppercase characters into lowercase characters and this class must respect
the IO API, means we must be able to wrap this class into BufferedInputStream or others.
package example.structure.decorator.ex3;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
39 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
5. Facade Pattern
Facade as the name suggests means the face of the building. The people walking past the road can only see
this glass face of the building. They do not know anything about it, the wiring, the pipes and other
complexities. The face hides all the complexities of the building and displays a friendly face.
This is how facade pattern is used. It hides the complexities of the system and provides an interface to the
client from where the client can access the system. In Java, the interface JDBC can be called a facade. We
as users or clients create connection using the “java.sql.Connection” interface, the implementation of
which we are not concerned about. The implementation is left to the vendor of driver.
A façade is an object that provides a simplified interface to a larger body of code, such as a class library. A
façade can:
1. make a software library easier to use and understand, since the façade has convenient methods for
common tasks;
2. make code that uses the library more readable, for the same reason;
3. reduce dependencies of outside code on the inner workings of a library, since most code uses the
façade, thus allowing more flexibility in developing the system;
4. Wrap a poorly designed collection of APIs with a single well-designed API.
40 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Participants
Example:
//Client
package example.structure.facade;
import java.awt.*;
import java.awt.event.*;
public DBFrame() {
super("Database demonstration");
setGUI();
db = new Database("org.gjt.mm.mysql.Driver");
db.Open("jdbc:mysql://127.0.0.1:3306/student", "root", "root");
String tnames[] = db.getTableNames();
loadList(Tables, tnames);
String queryText = "SELECT * FROM Employee";
query.setText(queryText);
}
// ------------------------------------
private void setGUI() {
setBackground(Color.lightGray);
setLayout(new BorderLayout());
Panel pn = new Panel();
add("North", pn);
pn.setLayout(new GridLayout(1, 3));
pn.add(new Label("Tables"));
pn.add(new Label("Columns"));
pn.add(new Label("Data"));
Panel pc = new Panel();
add("Center", pc);
pc.setLayout(new GridLayout(1, 3));
pc.add(Tables = new java.awt.List(15));
pc.add(Columns = new java.awt.List(15));
pc.add(Data = new java.awt.List(15));
Tables.addItemListener(this);
Columns.addItemListener(this);
Panel ps = new Panel();
add("South", ps);
41 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
ps.add(query = new TextArea("", 3, 40));
addPanel(ps, Search = new Button("Run Query"));
addPanel(ps, Quit = new Button("Quit"));
Search.addActionListener(this);
Quit.addActionListener(this);
setBounds(100, 100, 500, 300);
setVisible(true);
}
// ------------------------------------
private void addPanel(Panel ps, Component c) {
Panel p = new Panel();
ps.add(p);
p.add(c);
}
// ------------------------------------
private void loadList(java.awt.List list, String[] s) {
list.removeAll();
for (int i = 0; i < s.length; i++)
list.add(s[i]);
}
// ------------------------------------
public void actionPerformed(ActionEvent e) {
Object obj = e.getSource();
if (obj == Quit)
System.exit(0);
if (obj == Search)
clickedSearch();
}
// ------------------------------------
public void itemStateChanged(ItemEvent e) {
Object obj = e.getSource();
if (obj == Tables)
showColumns();
if (obj == Columns)
showData();
}
// ------------------------------------
private void showColumns() {
String cnames[] = db.getColumnNames(Tables.getSelectedItem());
loadList(Columns, cnames);
}
// ------------------------------------
private void showData() {
String colname = Columns.getSelectedItem();
String colval = db.getColumnValue(Tables.getSelectedItem(), colname);
Data.setVisible(false);
Data.removeAll();
Data.setVisible(true);
// System.out.println("Col Val:" + colval);
while (colval.length() > 0) {
Data.add(colval);
colval = db.getNextValue(Columns.getSelectedItem());
}
42 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
}
// ------------------------------------
private void clickedSearch() {
Results rs = db.Execute(query.getText());
queryDialog q = new queryDialog(this, rs);
q.show();
}
// ------------------------------------
static public void main(String argv[]) {
new DBFrame();
}
}
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
// -------------------------------------
private void makeTables() {
tables = new ArrayList();
String t[] = results.getMetaData();// to get column names
tables.add(t);
while (results.hasMoreElements()) // to get column values
{
tables.add(results.nextElement());
}
}
43 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
// -------------------------------------
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
// -------------------------------------
class textPanel extends Panel {
public void paint(Graphics g) {
String s[];
int x = 0;
int y = g.getFontMetrics().getHeight();
int deltaX = (int) 1.5f * (g.getFontMetrics().stringWidth("wwwwwwwwwwwwww"));
for (int i = 0; i < tables.size(); i++) {
s = (String[]) tables.get(i);
for (int j = 0; j < s.length; j++) {
String st = s[j];
g.drawString(st, x, y);
x += deltaX;
}
x = 0;
y += g.getFontMetrics().getHeight();
if (i == 0)
y += g.getFontMetrics().getHeight();
}
}
}
}
//Façade Class : Database
package example.structure.facade;
import java.sql.*;
import java.util.ArrayList;
class Database {
Connection con;
Results results;
DatabaseMetaData dma;
String catalog = null;
String types[];
String database_url;
// -----------------------------------
public void close() {
try {
con.close();
} catch (Exception e) {
System.out.println("close error");
}
44 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
}
// -----------------------------------
database_url = url;
try {
con = DriverManager.getConnection(url, user, password);
dma = con.getMetaData(); // get the meta data
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
// -----------------------------------
public void reOpen() {
try {
con = DriverManager.getConnection(database_url);
dma = con.getMetaData(); // get the meta data
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
// -----------------------------------
public String[] getTableNames() {
String[] tbnames = null;
ArrayList tname = new ArrayList();
// add the table names to a Vector
// since we don't know how many there are
try {
// getTables(String catalog, String schemaPattern,
// String tableNamePattern, String[] types)
results = new Results(dma.getTables(catalog, null, "%", types));
} catch (Exception e) {
System.out.println(e);
}
while (results.hasMoreElements())
tname.add(results.getColumnValue("TABLE_NAME"));
// -----------------------------------
public String[] getTableMetaData() {
// return the table type information
results = null;
try {
results = new Results(dma.getTables(catalog, null, "%", types));
} catch (Exception e) {
System.out.println(e.getMessage());
}
return results.getMetaData();
}
45 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
// -----------------------------------
public String[] getColumnMetaData(String tablename) {
// return the data on a column
results = null;
try { // getColumns(String catalog, String schemaPattern,
// String tableNamePattern, String columnNamePattern)
results = new Results(dma
.getColumns(catalog, null, tablename, null));
} catch (Exception e) {
System.out.println(e.getMessage());
}
return results.getMetaData();
}
// -----------------------------------
public String[] getColumnNames(String table) {
// return an array of Column names
String[] tbnames = null;
ArrayList tname = new ArrayList();
try {
results = new Results(dma.getColumns(catalog, null, table, null));
while (results.hasMoreElements())
tname.add(results.getColumnValue("COLUMN_NAME"));
} catch (Exception e) {
System.out.println(e);
}
tbnames = new String[tname.size()];
for (int i = 0; i < tname.size(); i++)
tbnames[i] = (String) tname.get(i);
return tbnames;
}
// -----------------------------------
public String getColumnValue(String table, String columnName) {
// return the value of a given column
String res = null;
try {
if (table.length() > 0)
results = Execute("Select " + columnName + " from " + table
+ " order by " + columnName);
if (results.hasMoreElements())
res = results.getColumnValue(columnName);
} catch (Exception e) {
System.out.println("Column value error" + columnName
+ e.getMessage());
}
return res;
}
// -----------------------------------
public String getNextValue(String columnName) {
// return the next value in that column
// using the remembered Results
String res = "";
try {
if (results.hasMoreElements())
res = results.getColumnValue(columnName);
} catch (Exception e) {
46 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
System.out.println("next value error" + columnName + e.getMessage());
}
return res;
}
// -----------------------------------
public Results Execute(String sql) {
// execute an SQL query on this database
results = null;
try {
Statement stmt = con.createStatement();
results = new Results(stmt.executeQuery(sql));
} catch (Exception e) {
System.out.println("execute error: " + e.getMessage());
}
return results;
}
}
import java.sql.*;
class Results {
// this class is a higher level abstraction
// of the JDBC ResultSet object
ResultSet rs;
ResultSetMetaData rsmd;
int numCols;
// -----------------------------------
public String[] getMetaData() {
// returns an array of all the column names
// or other meta data
String md[] = new String[numCols];
try {
for (int i = 1; i <= numCols; i++)
md[i - 1] = rsmd.getColumnName(i);
} catch (Exception e) {
System.out.println("meta data error" + e.getMessage());
}
return md;
}
// -----------------------------------
public boolean hasMoreElements() {
try {
return rs.next();
47 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
} catch (Exception e) {
System.out.println("next error " + e.getMessage());
return false;
}
}
// -----------------------------------
public String[] nextElement() {
// copies contents of row into string array
String[] row = new String[numCols];
try {
for (int i = 1; i <= numCols; i++)
row[i - 1] = rs.getString(i);
} catch (Exception e) {
System.out.println("next element error" + e.getMessage());
}
return row;
}
// -------------------------------------
public String getColumnValue(String columnName) {
String res = "";
try {
res = rs.getString(columnName);
} catch (Exception e) {
System.out.println("Column value error:" + columnName
+ e.getMessage());
}
return res;
}
// -------------------------------------
public String getColumnValue(int i) {
String res = "";
try {
res = rs.getString(i);
} catch (Exception e) {
System.out.println("Column value error: " + i + " "
+ e.getMessage());
}
return res;
}
// ----------------------------------------------
public void finalize() {
try {
rs.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
These simple classes allow us to write a program for opening a database, displaying its table names,
column names and contents, and running simple SQL query on the database.
48 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
49 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
6. Flyweight Pattern
This pattern states about a mechanism by which you can avoid creating a large number of object instances
to represent the entire system. To decide if some part of your program is a candidate for using Flyweights,
consider whether it is possible to remove some data from the class and make it extrinsic. If this makes it
possible to reduce greatly the number of different class instances your program needs to maintain, this
might be a case where Flyweights will help.
The typical example you can see on this in every book will be of folders. The folder with name of each of
the company employee on it, so, the attributes of class Folder are: ‘Selected’ , ‘Not Selected’ and the third
one is ‘employeeName’. With this methodology, we will have to create 2000 folder class instances for
each of the employees. This can be costly, so we can create just two class instances with attributes
‘selected’ and ‘not selected’ and set the employee’s name by a method like:
setNameOnFolder(String name);
This way, the instances of class folder will be shared and you will not have to create multiple instances for
each employee.
50 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Participants
q Flyweight
o Declares an interface through which flyweights can receive and act on extrinsic state.
q ConcreteFlyweight
o Implements the Flyweight interface and adds storage for intrinsic state, if any. A
ConcreteFlyweight object must be sharable. Any state it stores must be intrinsic, that is, it
must be independent of the ConcreteFlyweight object's context.
q UnsharedConcreteFlyweight
o Not all Flyweight subclasses need to be shared. The Flyweight interface enables sharing,
but it doesn't enforce it. It is common for UnsharedConcreteFlyweight objects to have
ConcreteFlyweight objects as children at some level in the flyweight object structure.
q FlyweightFactory
o Creates and manages flyweight objects.
o Ensures that flyweight are shared properly. When a client requests a flyweight, the
FlyweightFactory objects supplies an existing instance or creates one, if none exists.
q Client
o Maintains a reference to flyweight(s).
o computes or stores the extrinsic state of flyweight(s).
Example:
Suppose we want to draw a small folder icon with a name under it for each person in a an organization. If
this is a large organization, there could be a large number of such icons, but they are actually all the same
graphical image. Even if we have two icons, one for “is Selected” and one for “not Selected” the number
of different icons is small.
In such a system, having an icon object for each person, with its own coordinates, name and selected state
is a waste of resources. Instead, we’ll create a FolderFactory that returns either the selected or the
unselected folder drawing class, but does not create additional instances once one of each has been created.
Since this is such a simple case, we just create them both at the outset and then return one or the other:
For cases where more instances could exist, the factory could keep a table of the ones it had already
created and only create new ones if they weren’t already in the table.
The unique thing about using Flyweights, however, is that we pass the coordinates and the name to be
drawn into the folder when we draw it. These coordinates are the extrinsic data that allow us to share the
folder objects, and in this case create only two instances. The complete folder class shown below simply
creates a folder instance with one background color or the other and has a public Draw method that draws
the folder at the point you specify.
To use a Flyweight class like this, your main program must calculate the position of each folder as part of
its paint routine and then pass the coordinates to the folder instance. This is actually rather common, since
you need a different layout depending on the window’s dimensions, and you would not want to have to
keep telling each instance where its new location is going to be. Instead, we compute it dynamically during
the paint routine.
51 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
// Flyweight interface
package example.structure.flyweight;
import java.awt.*;
import java.awt.*;
class FolderFactory {
Folder unSelected, selected;
public FolderFactory() {
Color brown = new Color(0x5f5f1c);
selected = new Folder(brown);
unSelected = new Folder(Color.yellow);
}
// -------------------------------
public Folder getFolder(boolean isSelected) {
if (isSelected)
return selected;
else
return unSelected;
}
}
}
// Concrete Flyweight class
package example.structure.flyweight;
import java.awt.*;
import javax.swing.*;
public Folder(Color c) {
color = c;
}
// -------------------------------
public void draw(Graphics g, int tx, int ty, String name) {
g.setColor(Color.black); // outline
g.drawRect(tx, ty, W, H);
g.drawString(name, tx, ty + H + 15); // title
g.setColor(Color.white);
g.drawLine(tx, ty, tx + W, ty);
Polygon poly = new Polygon();
poly.addPoint(tx + tableft, ty);
poly.addPoint(tx + tableft + tabslant, ty - tabheight);
poly.addPoint(tx + tabwidth - tabslant, ty - tabheight);
poly.addPoint(tx + tabwidth, ty);
g.setColor(Color.black);
52 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
g.drawPolygon(poly);
g.setColor(color); // fill rectangle
g.fillRect(tx + 1, ty + 1, W - 1, H - 1);
g.fillPolygon(poly);
g.setColor(Color.white);
g.drawLine(tx, ty, tx + W, ty);
g.setColor(Color.lightGray); // bend line
g.drawLine(tx + 1, ty + H - 5, tx + W - 1, ty + H - 5);
g.setColor(Color.black); // shadow lines
g.drawLine(tx, ty + H + 1, tx + W - 1, ty + H + 1);
g.drawLine(tx + W + 1, ty, tx + W + 1, ty + H);
g.setColor(Color.white); // highlight lines
g.drawLine(tx + 1, ty + 1, tx + W - 1, ty + 1);
g.drawLine(tx + 1, ty + 1, tx + 1, ty + H - 1);
}
}
// Client class
package example.structure.flyweight;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
// -------------------------------
public FlyCanvas() {
super("Flyweight Canvas");
loadNames();
loadFolders();
JPanel jp = new JPanel();
getContentPane().add(jp);
setSize(new Dimension(300, 300));
addMouseMotionListener(this);
addWindowStateListener(this);
setVisible(true);
repaint();
}
// -------------------------------
private void loadFolders() {
folders = new ArrayList();
for (int i = 0; i < names.size(); i++) {
folders.add(fact.getFolder(false));
}
}
// -------------------------------
private void loadNames() {
53 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
names = new ArrayList();
fact = new FolderFactory();
names.add("Sumit");
names.add("Amit");
names.add("Pankaj");
names.add("Abhay");
names.add("Raj Kumar");
names.add("Shadab");
names.add("Vishal");
names.add("Pragya");
names.add("Daya Shanker");
names.add("Manoj");
selectedName = "";
// -------------------------------
public void paint(Graphics g) {
Folder f;
String name;
// -------------------------------
public void mouseMoved(MouseEvent e) {
int j = 0; // count number in row
int row = Top; // start in upper left
int x = Left;
// go through all the names and folders
for (int i = 0; i < names.size(); i++) {
// see if this folder contains the mouse
Rectangle r = new Rectangle(x, row, W, H);
if (r.contains(e.getX(), e.getY())) {
selectedName = (String) names.get(i);
repaint();
}
x = x + HSpace; // change to next posn
54 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
j++;
if (j >= HCount) { // reset for next row
j = 0;
row += VSpace;
x = Left;
}
}
// -------------------------------
static public void main(String[] argv) {
new FlyCanvas();
}
}
55 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
7. Proxy Pattern
The Proxy pattern is used when you need to represent a complex object by a simpler one. If creating an
object is expensive in time or computer resources, Proxy allows you to postpone this creation until you
need the actual object. A Proxy usually has the same methods as the object it represents, and once the
object is loaded, it passes on the method calls from the Proxy to the actual object.
Proxies can also be used to distinguish between requesting an instance of an object and the actual need to
access it. For example, program initialization may set up a number of objects, which may not all be used
right away. In that case, the proxy can load the real object only when it is needed.
Let’s consider the case of a large image that a program needs to load and display. When the program starts,
there must be some indication that an image is to be displayed so that the screen lays out correctly, but the
actual image display can be postponed until the image is completely loaded. This is particularly important
in programs such as word processors and web browsers that lay out text around the images even before the
images are available.
An image proxy can note the image and begin loading it in the background, while drawing a simple
rectangle or other symbol to represent the image’s extent on the screen before it appears. The proxy can
even delay loading the image at all until it receives a paint request, and only then begin the process.
Structure of Proxy Pattern :
56 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Participants:
q Proxy
o Maintains a reference that lets the proxy access the real subject. Proxy may refer to a
Subject if the RealSubject and Subject interfaces are the same.
o Provides an interface identical to Subject's so that a proxy can be substituted for the real
subject.
o Controls access to the real subject and may be responsible for creating and deleting it.
o Remote proxies are responsible for encoding a request and its arguments and for sending the
encoded request to the real subject in a different address space.
o Virtual proxies may cache additional information about the real subject so that they can
postpone accessing it. For example, the ImageProxy caches the real images's extent.
o Protection proxies check that the caller has the access permissions required to perform a
request.
q Subject
o Defines the common interface for RealSubject and Proxy so that a Proxy can be used
anywhere a RealSubject is expected.
q RealSubject
o Defines the real object that the proxy represents.
Example: In this example program, we create a simple program to display an image on a JPanel when it is
loaded. Rather than loading the image directly, we use a class we call ImageProxy to defer loading and
draw a rectangle around the image area until loading is completed.
//ImageProxy
package example.structure.proxy;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import javax.swing.JPanel;
57 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
imageCheck.start(); // start 2nd thread monitor
// this begins actual image loading
try {
tracker.waitForID(0, 1);
} catch (InterruptedException e) {
}
}
// ------------------------------------
public void paint(Graphics g) {
if (tracker.checkID(0)) {
height = img.getHeight(null); // get height
width = img.getWidth(null); // and width
g.setColor(Color.lightGray); // erase box
g.fillRect(0, 0, width, height);
g.drawImage(img, 0, 0, this); // draw loaded image
} else {
// draw box outlining image if not loaded yet
g.setColor(Color.black);
g.drawRect(1, 1, width - 2, height - 2);
System.out.println("sss");
}
}
// ------------------------------------
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
//Client
package example.structure.proxy;
import javax.swing.*;
import java.awt.*;
public class ProxyDisplay extends JFrame {
public ProxyDisplay() {
super("Display proxied image");
JPanel p = new JPanel();
getContentPane().add(p);
p.setLayout(new BorderLayout());
ImageProxy image = new ImageProxy("puppy.jpg", 321, 271);
p.add("Center", image);
p.add("North", new Label(" "));
p.add("West", new Label(" "));
58 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
setSize(370, 350);
setVisible(true);
}
// ------------------------------------
static public void main(String[] argv) {
new ProxyDisplay();
}
}
We create the instance of the ImageProxy just as we would have for an Image, and that we add it to the
enclosing JPanel as we would an actual image. The ImageProxy class sets up the image loading and creates
a MediaTracker object to follow the loading process within the constructor:
The waitForID method of the MediaTracker actually initiates loading. In this case, we put in a minimum
wait time of 1 msec so that we can minimize apparent program delays. The constructor also creates a
separate thread imageCheck that checks the loading status every few milliseconds, and starts that thread
running.
For the purposes of this illustration program, we slowed the polling time down to 1 second so you can see
the program draw the rectangle and then refresh the final image.
Finally, the Proxy is derived from the JPanel component, and therefore, naturally has a paint method. In
this method, we draw a rectangle if the image is not loaded. If the image has been loaded, we erase the
rectangle and draw the image instead.
59 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Behavioral Patterns
Behavioral patterns are those, which are concerned with interactions between the objects. The interactions
between the objects should be such that they are talking to each other and still are loosely coupled. 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.
The responsibility of handling the request data is given to any of the members (object) of the “chain”. If
the first link of the chain cannot handle the responsibility, it passes the request data to the next level in the
chain, i.e. to the next link. The process continues till some object in the chain handles the responsibility or
the request reaches to the last object in the chain. If even last object does not handle the responsibility then
request is ignored.
For readers, familiar with concepts of Java, this is similar to what happens in an Exception Hierarchy.
Another example of this is handling KeyPressed event. Suppose the event occurs when a component is
selected, which is part of a panel and panel is part of the Frame. The event is received successively by:
60 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Structure of Chain of Responsibility Pattern:
Participants
q Handler
o Defines an interface for handling the requests.
o Optionally implements the successor link.
q ConcreteHandler
o Handles requests it is responsible for.
o Can access its successor
o If the ConcreteHandler can handle the request, it does so; otherwise it forwards the request
to its successor.
q Client
o Initiates the request to a ConcreteHandler object on the chain
Example:
Let’s consider a simple system for displaying the results of typed in requests. These requests can be
· Image filenames
· General filenames
· Color Names
· Other commands
In the first three cases, we can display a concrete result of the request, and in the last case, we can only display the
request text itself.
61 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
The System responds to commands as follows:
If we type in anything that is neither a filename nor a color, that text is displayed in the right-hand list box. This
sequence of steps is shown below:
The classes/interfaces to implement this simple chain of responsibility program are described below.
//Client: Chainer
//It sets up the GUI and the chain of responsibility
package example.behavioural.chain;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
// --------------------------------------
public Chainer() {
super("Chain demo");
JPanel jp = new JPanel();
jp.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(jp);
jp.setLayout(new GridLayout(1, 3));
JPanel left = new JPanel();
jp.add(left);
left.setLayout(new GridLayout(2, 1));
62 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
// create send panel and image display panel
sender = new Sender();
imager = new Imager();
left.add(imager);
left.add(sender);
// create file list and color panels
JPanel mid = new JPanel();
jp.add(mid);
mid.setBorder(new EmptyBorder(5, 5, 5, 5));
mid.setLayout(new GridLayout(2, 1));
fileList = new FileList();
// -----------------------------------------
static public void main(String argv[]) {
new Chainer();
}
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;
// ----------------------------------
public Sender() {
setLayout(new GridLayout(2, 1));
JPanel tp = new JPanel();
JPanel bp = new JPanel();
add(tp);
add(bp);
63 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
tx = new JTextField(10);
tp.add(tx);
Send = new JButton("Send");
bp.add(Send);
Send.addActionListener(this);
setBorder(new TitledBorder("Send commands"));
}
// ----------------------------------
public void actionPerformed(ActionEvent e) {
String file = tx.getText();
if ((file.length() > 0) && (nextChain != null))
nextChain.sendToChain(file);
}
// ----------------------------------
public void addChain(Chain c) {
nextChain = c;
}
// ----------------------------------
public void sendToChain(String mesg) {
} // this one does nothing
// ----------------------------------
import java.awt.*;
import java.io.File;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;
public Imager() {
super();
loaded = false;
setBorder(new BevelBorder(BevelBorder.RAISED));
}
// ------------------------------------------
public void addChain(Chain c) {
nextChain = c; // next in chain of resp
}
// ------------------------------------------
public void sendToChain(String mesg) {
// if mesg is a JPEG file
// load it and display it.
64 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
if (mesg.endsWith(".jpg") && findImage(mesg))
loadImage(mesg);
else
// Otherwise, pass request along chain
nextChain.sendToChain(mesg);
}
// ------------------------------------------
public Chain getChain() {
return nextChain;
}
// ------------------------------------------
public void paint(Graphics g) {
if (loaded) {
g.drawImage(img, 0, 0, this);
}
}
// ------------------------------------------
private void loadImage(String file) {
loaded = false;
MediaTracker tracker = new MediaTracker(this);
img = Toolkit.getDefaultToolkit().getImage(file);
tracker.addImage(img, 0); // watch for image loading
// this begins actual image loading
try {
tracker.waitForID(0, 1);
} catch (InterruptedException e) {
}
loaded = true;
validate();
repaint();
}
// ------------------------------------------
private boolean findImage(String file) {
File dir = new File(System.getProperty("user.dir"));
boolean found = false;
String files[] = dir.list();
int i = 0;
while ((!found) && (i < files.length)) {
found = file.equals(files[i]);
if (!found)
i++;
}
return (found);
}
}
65 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//Concrete Handler: ColorImage
package example.behavioural.chain;
import java.awt.Color;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
// -----------------------------------
public ColorImage() {
super();
setBorder(new LineBorder(Color.black));
}
// -----------------------------------
public void addChain(Chain c) {
nextChain = c;
}
// -----------------------------------
public void sendToChain(String mesg) {
Color c = getColor(mesg);
if (c != null) {
setBackground(c);
repaint();
} else {
if (nextChain != null) {
nextChain.sendToChain(mesg);
}
}
}
// -----------------------------------
private Color getColor(String mesg) {
String lmesg = mesg.toLowerCase();
Color c = null;
if (lmesg.equals("red"))
c = Color.red;
if (lmesg.equals("blue"))
c = Color.blue;
if (lmesg.equals("green"))
c = Color.green;
return c;
}
// -----------------------------------
public Chain getChain() {
return nextChain;
}
}
66 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//Concrete Handler: FileList
// Selects the specified file if it is present in the list
package example.behavioural.chain;
import java.io.File;
public FileList() {
super();
String tmp = "";
File dir = new File(System.getProperty("user.dir"));
files = dir.list();
for (int i = 0; i < files.length; i++) {
for (int j = i; j < files.length; j++) {
if (files[i].toLowerCase().compareTo(files[j].toLowerCase()) > 0) {
tmp = files[i];
files[i] = files[j];
files[j] = tmp;
}
}
}
for (int i = 0; i < files.length; i++)
add(files[i]);
}
// ---------------------------------------
public void sendToChain(String mesg) {
System.out.println("in filelist");
boolean found = false;
int i = 0;
while ((!found) && (i < files.length)) {
found = files[i].equals(mesg);
if (!found)
i++;
}
System.out.println("i =" + i);
if (found) {
this.select(i);
} else {
if (nextChain != null)
nextChain.sendToChain(mesg);
}
}
// ------------------------------------------
public void addChain(Chain c) {
nextChain = c; // next in chain of resp
}
}
67 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//Concrete Handler: RestList
// Unhandled command is siply added to the rightmost list.
package example.behavioural.chain;
import java.awt.List;
public RestList() {
super(10); // arg to JawtList
}
The main purpose for this pattern, like a number of others, is to reduce coupling between objects. An
object only needs to know how to forward the request to other objects.
This approach also gives you added flexibility in distributing responsibilities between objects. Any object
can satisfy some or all of the requests, and you can change both the chain and the responsibilities at run
time.
An advantage is that there may not be any object that can handle the request, however, the last object in the
chain may simply discard any requests it can’t handle.
Finally, since Java can not provide multiple inheritance, the basic Chain class needs to be an interface
rather than an abstract class, so that the individual objects can inherit from another useful hierarchy, as we
did here by deriving them all from JPanel. The disadvantage of this approach is that you often have to
implement the linking, sending and forwarding code in each module separately.
68 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
2. Command Pattern
This is another of the data-driven pattern. The client invokes a particular module using a command (which
is an object). The client passes a request, this request gets propagated as a command. The command
request maps to particular modules. According to the command, a module is invoked.
This pattern is different from the Chain of Responsibility in a way that, in the earlier one, the request
passes through each of the object before finding an object that can take the responsibility. The command
pattern however finds the particular object according to the command and invokes only that one.
It’s like there is a server having a lot of services to be given, and on Demand (or on command), it caters to
that service for that particular client.
A classic example of this is a restaurant. A customer goes to restaurant and orders the food according to
his/her choice. The waiter/waitress takes the order (command, in this case) and hands it to the cook in the
kitchen. The cook can make several types of food and so, he/she prepares the ordered item and hands it
over to the waiter/waitress who in turn serves to the customer.
69 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
3.2 Structure of Command Pattern
Participants
q Command
o Declares an interface for executing an operation.
q ConcreteCommand
o Defines a binding between a Receiver object and an action.
o Implements execute by invoking the corresponding operation(s) on Receiver.
q Client
o Creates a ConcreteCommand object and sets its receiver.
q Invoker
o Asks the command to carry out the request.
q Receiver
o knows how to perform the operations associated with carrying out a request. Any class may
server as receiver
70 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Example 1:
//Command Interface
package example.behavioural.command.ex1;
interface Command {
public void execute();
}
//Client
package example.behavioural.command.ex1;
import java.awt.*;
import java.awt.event.*;
Panel p;
Frame fr;
// -----------------------------------------
public ExtrnCommand() {
super("Frame with external commands");
fr = this; // save frame object
MenuBar mbar = new MenuBar();
setMenuBar(mbar);
mnuFile = new Menu("File", true);
mbar.add(mnuFile);
mnuOpen = new FileOpenCommand("Open...", this);
mnuFile.add(mnuOpen);
mnuExit = new FileExitCommand("Exit");
mnuFile.add(mnuExit);
mnuOpen.addActionListener(this);
mnuExit.addActionListener(this);
p = new Panel();
add(p);
btnRed = new BtnRedCommand("Red", p);
p.add(btnRed);
btnRed.addActionListener(this);
setBounds(100, 100, 200, 100);
setVisible(true);
}
// -----------------------------------------
public void actionPerformed(ActionEvent e) {
Command obj = (Command) e.getSource();
obj.execute();
}
// -----------------------------------------
static public void main(String argv[]) {
new ExtrnCommand();
}
}
71 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//ConcreteCommand as well as Invoking Client
package example.behavioural.command.ex1;
import java.awt.*;
//------------------------------------------
//ConcreteCommand as well as Invoking Client
package example.behavioural.command.ex1;
import java.awt.*;
72 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Example 2: The above example is refined so as to ensure that the command objects are different from the
invoking clients. Rather than having the command is part of the menu or button, we make the menu and
button classes containers for a Command object that exists separately. We thus make UI elements that
implement a CommandHolder interface. This interface indicates that there is a method to put a command
object into the invoking object and a method to fetch that Command object and call its execute method.
//Command interface
package example.behavioural.command.ex2;
public interface Command {
public void execute();
}
//CommandHolder interface
package example.behavioural.command.ex2;
public interface CommandHolder {
public void setCommand(Command comd);
// Invoker
import java.awt.*;
import javax.swing.*;
package example.behavioural.command.ex2;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
// -----------------------
public CmdMenu(String name, JFrame frm) {
super(name);
frame = frm;
}
// -----------------------
public void setCommand(Command comd) {
menuCommand = comd;
}
// -----------------------
public Command getCommand() {
return menuCommand;
}
}
73 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
// Invoker
package example.behavioural.command.ex2;
import java.awt.*;
import javax.swing.*;
//ConcreteCommand
package example.behavioural.command.ex2;
//ConcreteCommand
package example.behavioural.command.ex2;
import java.awt.*;
import javax.swing.*;
// ------------------------------
public void execute() {
FileDialog fDlg = new FileDialog(frame, "Open file");
fDlg.setVisible(true);
}
}
74 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//ConcreteCommand
package example.behavioural.command.ex2;
import java.awt.*;
import javax.swing.*;
//Client
package example.behavioural.command.ex2;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
// -----------------------------------------
public FullCommand() {
super("Frame with external commands");
fr = this; // save frame object
JPanel jp = new JPanel();
getContentPane().add(jp);
JMenuBar mbar = new JMenuBar();
setJMenuBar(mbar);
mnuOpen.setCommand(new FileCommand(this));
75 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
mnuExit = new CmdMenu("Exit", this);
mnuExit.setCommand(new ExitCommand());
mnuFile.add(mnuExit);
mnuOpen.addActionListener(this);
mnuExit.addActionListener(this);
jp.add(btnRed);
btnRed.addActionListener(this);
setBounds(100, 100, 200, 100);
setVisible(true);
}
// -----------------------------------------
public void actionPerformed(ActionEvent e) {
CommandHolder obj = (CommandHolder) e.getSource();
obj.getCommand().execute();
}
// -----------------------------------------
static public void main(String argv[]) {
new FullCommand();
}
}
76 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
3. Iterator Pattern
]In object-oriented programming, the Iterator pattern is a design pattern in which iterators are used to
access the elements of an aggregate object sequentially without exposing its underlying representation. An
Iterator object encapsulates the internal structure of how the iteration occurs.
Iterator should be implemented as an interface. This allows the user to implement it anyway its easier for
him/her to return data.
Participants
q Iterator
o Defines an interface for accessing and traversing elements.
q ConcreteIterator
o Implements the Iterator interface.
o Keeps track of the current position in the traversal of the aggregate.
q Aggregate
o Defines an interface for creating an Iterator object.
q ConcreteAggregate
o Implements the Iterator creation interface to return an instance of the proper ConcreteIterator.
Example:
//Iterator Interface
public interface Iterator {
void first();
void next();
boolean isDone();
Object currentItem();
}
77 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//Aggregate Interface
import java.util.Vector;
package example.behavioural.iterator;
import java.util.Vector;
78 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//ConcreteAggregateA
package example.behavioural.iterator;
//ConcreateIteratorB
package example.behavioural.iterator;
79 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//Client
package example.behavioural.iterator;
public class IteratorExample {
public static void main(String[] args) {
Aggregate testA = new ConcreteAggregateA();
testA.append(new Integer(1));
testA.append(new Integer(2));
testA.append(new Integer(3));
testA.append(new Integer(4));
testA.append(new Integer(5));
Aggregate testB = new ConcreteAggregateB();
testB.append(new Integer(1));
testB.append(new Integer(2));
testB.append(new Integer(3));
testB.append(new Integer(4));
testB.append(new Integer(5));
System.out.println("Print Test A:");
Iterator iterA = testA.createIterator();
iterA.first();
while (!iterA.isDone()) {
Integer n = (Integer) iterA.currentItem();
iterA.next();
System.out.println("Value: " + n);
}
System.out.println("Print Test B:");
Iterator iterB = testB.createIterator();
iterB.first();
while (!iterB.isDone()) {
Integer n = (Integer) iterB.currentItem();
iterB.next();
System.out.println("Value: " + n);
}
}
}
Output:
Print Test A: Print Test B:
Value: 1 Value: 5
Value: 2 Value: 4
Value: 3 Value: 3
Value: 4 Value: 2
Value: 5 Value: 1
Internal Iterators: Internal iterators move through the entire collection, performing some
operation on each element directly, without any specific request from the user. Internal iterators
may perform operations like normalizing a collection of data values to lie between 0 and 1 or
converting all of the strings to a particular case.
Data modification. The most significant question iterators may raise is the question of iterating through
data while it is being changed. If your code is wide ranging and only occasionally moves to the next
element, it is possible that an element might be added or deleted from the underlying collection while you
are moving through it. It is also possible that another thread could change the collection. There are no
simple answers to this problem. You can make an enumeration thread-safe by declaring the loop to be
synchronized, but if you want to move through a loop using an Enumeration, and delete certain items, you
must be careful of the consequences. Deleting or adding an element might mean that a particular element is
skipped or accessed twice, depending on the storage mechanism you are using.
80 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
4. Mediator Pattern
Object oriented design encourages the distribution of behavior among objects. Such distribution can result
in an object structure with many connections between objects; in the worst case, every object ends up
knowing about every other.
Though partitioning a system into many objects generally enhances reusability, proliferating
interconnections tend to reduce it again. Lots of interconnection s make it less likely that an object can
work without the support of others- the system acts as though as though it were monolithic. Moreover, it
can be difficult to change the system’s behavior in any significant way, since behavior is distributed among
many objects.
You can avoid these problems by encapsulating collective behavior in a separate mediator object. A
mediator is responsible for controlling and coordinating the interactions of a group of objects. The
mediator serves as an intermediary that keeps objects in the group from referring to each other explicitly.
The objects only know the mediator, thereby reducing the number of interconnections.
A very common example can be airplanes interacting with the control tower and not among themselves.
The control tower knows exactly, where each of the airplanes is, and guides them whereas the airplanes
have their own responsibilities of landing and takeoff.
Participants
q Mediator
o Defines an interface for communicating with Colleague objects.
q ConcreteMediator
o Implements cooperative behavior by coordinating Colleague objects.
o Knows and maintains its colleagues.
q Colleague classes
o Each Colleague class knows its Mediator object
o Each colleague communicates with its mediator whenever it would have otherwise
communicated with another colleague
81 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//Mediator
package example.behavioural.mediator;
interface Mediator {
public void send(String id, String message);
}
//ConcreteMediator
class ConcreteMediator implements Mediator {
private Map<String, Colleague> colleagues = new HashMap<String, Colleague>();
public void registerColleague(Colleague c) {
c.registerMediator(this);
colleagues.put(c.getId(), c);
}
public void send(String id, String message) {
colleagues.get(id).receive(message);
}
}
// Colleague
package example.behavioural.mediator;
public class Colleague {
private Mediator mediator;
private String id;
public Colleague(String id) {
this.id = id;
}
public void registerMediator(Mediator mediator) {
this.mediator = mediator;
}
public String getId() {
return id;
}
public void send(String id, String message) {
System.out.println("Sending message from " + this.id + " to " + id
+ ": " + message);
mediator.send(id, message);
// Dispatch the actual communication to the mediator!!!
}
public void receive(String message) {
System.out.println("Received message by " + id + ": " + message);
}
}
//Client
package example.behavioural.mediator;
class MediatorExample {
public static void main(String[] args) {
Colleague rene = new Colleague("rene");
Colleague toni = new Colleague("toni");
Colleague kim = new Colleague("kim");
ConcreteMediator m = new ConcreteMediator();
m.registerColleague(rene);
m.registerColleague(toni);
m.registerColleague(kim);
kim.send("toni", "Hello world.");
rene.send("kim", "Greetings!");
}
}
82 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
5. Memento Pattern
The memento pattern is a software design pattern that provides the ability to restore an object to its
previous state (undo by rollback). The objective of this pattern is to capture and externalize an object’s
internal state without violating encapsulation so that the object can be restores to this state later. This is
required when implementing checkpoints and undo mechanisms that let users back out of tentative
operations or recover from errors.
The memento pattern is used by two objects: the originator and a caretaker. The originator is some object
that has an internal state. The caretaker is going to do something to the originator, but wants to be able to
undo the change. The caretaker first asks the originator for a memento object. Then it does whatever
operation (or sequence of operations) it was going to do. To rollback to the state before the operations, it
returns the memento object to the originator. The memento object itself is an opaque object (one which the
caretaker can not, or should not, change). When using this pattern, care should be taken if the originator
may change other objects or resources - the memento pattern operates on a single object.
Participants
q Memento
o Stores internal state of the Originator object. The memento may store as much or as little of
the originator's internal state as necessary at its originator's discretion.
o Protects against access by objects other than the originator. Mementos have effectively two
interfaces. Caretaker sees a narrow interface to the Memento -- it can only pass the
memento to the other objects. Originator, in contrast, sees a wide interface, one that lets it
access all the data necessary to restore itself to its previous state. Ideally, only the originator
that produces the memento would be permitted to access the memento's internal state.
q Originator
o Creates a memento containing a snapshot of its current internal state.
o Uses the memento to restore its internal state.
q Caretaker
o Is responsible for the memento's safekeeping.
o Never operates on or examines the contents of a memento.
83 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Example:
//Memento
package example.behavioural.memento;
class Memento {
private String state;
//Originator
package example.behavioural.memento;
class Originator {
private String state;
import java.util.ArrayList;
class Caretaker {
private ArrayList<Memento> savedStates = new ArrayList<Memento>();
84 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
//Client
package example.behavioural.memento;
85 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
6. Observer Pattern
The observer pattern (sometimes known as publish/subscribe) is a design pattern used to observe the
state of an object in a program. The pattern assumes one-to-many dependency between objects so that
when one object changes stste, all its dependent are notified and updates automatically.
The Observer pattern assumes that the object containing the data is separate from the objects that display
the data, and that these display objects observe changes in that data. When we implement the Observer
pattern, we usually refer to the data as the Subject and each of the displays as Observers. Each of these
observers registers its interest in the data by calling a public method in the Subject.
This pattern is commonly used in event handling system. In some programming languages, the issues
addressed by this pattern are handled in the native event handling syntax. The essence of this pattern is that
one or more objects (called observers or listeners or event handlers) are registered (or register
themselves) to observe an event which may be raised by the observed object (the subject). The object
(subject) which may raise an event generally maintains a collection of the observers.
When the event is raised each observer receives a callback i.e. the notify method of the object (observer)
passed as an argument to the listener registration method is invoked. The notify method may also be
passed some parameters (generally information about the event that is occurring) which can be used by the
observer.
Each concrete observer implements the notify method and as a consequence defines its own behavior when
the notification occurs.
The subject normally has a register method for adding a new listener and an unregister method for
removing an observer from the list of objects to be notified when the event is raised.
The observer pattern is also very often associated with the Model-view-controller (MVC) paradigm. In
MVC, the observer pattern is used to create a loose coupling between the model and the view. Typically, a
modification in the model triggers the notification of model observers which are actually the views.
This is used extensively in Swing. The JList, JTable, and JTree objects all operate as observers of a data
model. In fact, all of the visual components derived from JComponent can have this same division of labor
between the data and the visual representation.
86 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Structure of Observer Pattern
Participants
q Subject
o Knows its observers. Any number of Observer objects may observe a subject.
o Provides an interface for attaching and detaching Observer objects.
q ConcreteSubject
o Stores state of interest to ConcreteObserver objects.
o Sends a notification to its observers when its state changes.
q Observer
o Defines an updating interface for objects that should be notified of changes in a subject.
q ConcreteObserver
o Maintains a reference to a ConcreteSubject object.
o Stores state that should stay consistent with the subject's.
o Implements the Observer updating interface to keep its state consistent with the subject's.
87 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
two observers are: a colored panel and a list box. The color of the panel changes to the selected color and
the selected color gets added in the list box as shown below:
//Subject Interface
package example.behavioural.observer;
//Observer Interface
package example.behavioural.observer;
import javax.swing.*;
import java.util.*;
public class JListData extends AbstractListModel {
private Vector data;
public JListData() {
data = new Vector();
}
import javax.swing.*;
import java.awt.*;
88 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
public class ListFrame extends JFrame implements Observer {
private JList list;
private JPanel p;
private JScrollPane lsp;
private JListData listData;
public ListFrame(Subject s) {
super("Color List");
// put panel into the frmae
p = new JPanel(true);
getContentPane().add("Center", p);
p.setLayout(new BorderLayout());
// Tell the Subject we are interested
s.registerInterest(this);
// Create the list
listData = new JListData(); // the list model
list = new JList(listData); // the visual list
lsp = new JScrollPane(); // the scroller
lsp.getViewport().add(list);
p.add("Center", lsp);
lsp.setPreferredSize(new Dimension(100, 100));
setBounds(250, 100, 100, 100);
setVisible(true);
}
// --------------------------------
public void sendNotify(String s) {
listData.addElement(s);
}
}
//ConcreteObserver2
package example.behavioural.observer;
import javax.swing.*;
import java.awt.*;
public ColorFrame(Subject s) {
super("Colors");
getContentPane().add("Center", p);
s.registerInterest(this);
setBounds(100, 100, 100, 100);
font = new Font("Sans Serif", Font.BOLD, 14);
setVisible(true);
}
89 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
}
public void paint(Graphics g) {
g.setFont(font);
g.drawString(color_name, 20, 50);
}
}
//ConcreteSubject
package example.behavioural.observer;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.util.*;
// ------------------------------------------
public Watch2Windows() {
super("Change 2 other frames");
observers = new Vector(); // list of observing frames
JPanel p = new JPanel(true); // add panel to content pane
p.setLayout(new BorderLayout());
getContentPane().add("Center", p);
Box box = new Box(BoxLayout.Y_AXIS); // vertical box layout
p.add("Center", box);
box.add(red = new JRadioButton("Red")); // and 3 radio buttons
box.add(green = new JRadioButton("Green"));
box.add(blue = new JRadioButton("Blue"));
blue.addItemListener(this); // listen for clicks
red.addItemListener(this); // on radion buttons
green.addItemListener(this);
// make all part of same button group
ButtonGroup bgr = new ButtonGroup();
bgr.add(red);
bgr.add(green);
bgr.add(blue);
// put a Close button at the bottom of the frame
JPanel p1 = new JPanel();
p.add("South", p1);
p1.add(Close = new JButton("Close"));
Close.addActionListener(this); // listen for clicks on it
setBounds(200, 200, 200, 200);
pack();
// ---------create observers---------
cframe = new ColorFrame(this);
lframe = new ListFrame(this);
setVisible(true);
}
// -----------------------------------------
public void itemStateChanged(ItemEvent e) {
// responds to radio button clicks
// if the button is selected
90 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
if (e.getStateChange() == ItemEvent.SELECTED)
notifyObservers((JRadioButton) e.getSource());
}
// -----------------------------------------
private void notifyObservers(JRadioButton rad) {
// sends text of selected button to all observers
String color = rad.getText();
for (int i = 0; i < observers.size(); i++) {
((Observer) (observers.elementAt(i))).sendNotify(color);
}
}
// -----------------------------------------
public void registerInterest(Observer obs) {
// adds observer to list
observers.addElement(obs);
}
// -----------------------------------------
public void actionPerformed(ActionEvent e) {
// responds to close button
Object obj = e.getSource();
if (obj == Close)
System.exit(0);
}
// -----------------------------------------
static public void main(String[] argv) {
new Watch2Windows();
}
}
91 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
7. State Pattern
The state pattern is also known as the objects for states pattern. This pattern is used to represent the
states of an object. This allows an object to alter its behavior when its internal state changes. The object
will appear to change its class. This is a clean way for an object to partially change its type at runtime.
Known Usage
Most popular interactive drawing programs provide “tools” for performing operations by direct
manipulation. For example, a line drawing tool lets a user click and drag to create a new line. A selection
tool lets the user select shapes. We can use the state pattern to change the editor’s behavior depending on
the current tool.
We can define an abstract Tool class from which to define subclasses that implement tool specific
behavior. The drawing editor maintains a current Tool object and delegates requests to it. It replaces this
object when the user chooses a new tool, causing the behavior of drawing tool to change accordingly.
Participants
q Context
o Defines the interface of interest to clients.
o Maintains an instance of a ConcreteState subclass that defines the current state.
q State
o Defines an interface for encapsulating the behavior associated with a particular state of the
Context.
q Concrete State
o Each subclass implements a behavior associated with a state of the Context.
92 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Example:
//State
package example.behavioural.state;
//ConcreteState1
package example.behavioural.state;
class Stage {
private Actor actor = new HappyActor();
public void change() {
actor = new SadActor();
}
public void performPlay() {
actor.act();
}
}
//Client
package example.behavioural.state;
93 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
8. Strategy Pattern
The Strategy Pattern (also known as Policy Pattern) is a particular software design pattern, whereby
algorithms can be selected on-the-fly at runtime.
In some programming languages, such as those without polymorphism, the issues addressed by this pattern
are handled through forms of reflection, such as the native function pointer or function delegate syntax.
The strategy pattern is useful for situations where it is necessary to dynamically swap the algorithms used
in an application. The strategy pattern is intended to provide a means to define a family of algorithms,
encapsulate each one as an object, and make them interchangeable. The strategy pattern lets the algorithms
vary independently from clients that use them.
The Strategy pattern is much like the State pattern in outline, but a little different in intent. The Strategy
pattern consists of a number of related algorithms encapsulated in a driver class called the Context. Your
client program can select one of these differing algorithms or in some cases the Context might select the
best one for you. The intent, like the State pattern, is to switch easily between algorithms without any
monolithic conditional statements. The difference between State and Strategy is that the user generally
chooses which of several strategies to apply and that only one strategy at a time is likely to be instantiated
and active within the Context class. By contrast, as we have seen, it is likely that all of the different States
will be active at once and switching may occur frequently between them. In addition, Strategy ncapsulates
several algorithms that do more or less the same thing, while State encapsulates related classes that each do
something somewhat different. Finally, the concept of transition between different states is completely
missing in the Strategy pattern.
Participants
q Strategy (SortStrategy)
o Declares an interface common to all supported algorithms. Context uses this interface to call
the algorithm defined by a ConcreteStrategy.
q ConcreteStrategy (QuickSort, ShellSort, MergeSort)
o Implements the algorithm using the Strategy interface
q Context (SortedList)
o Is configured with a ConcreteStrategy object.
o Maintains a reference to a Strategy object.
o May define an interface that lets Strategy access its data.
94 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
package example.behavioural.strategy;
interface TaxStrategy {
public double extortCash(double income);
}
class CompanyTaxStrategy implements TaxStrategy {
private static final double RATE = 0.30;
public double extortCash(double income) {
return income * RATE ;
}
}
class EmployeeTaxStrategy implements TaxStrategy {
private static final double RATE = 0.45;
public double extortCash(double income) {
return income * RATE;
}
}
class TrustTaxStrategy implements TaxStrategy {
private static final double RATE = 0.40;
public double extortCash(double income) {
return income * RATE;
}
}
class TaxPayer {
public static final TaxStrategy EMPLOYEE = new EmployeeTaxStrategy();
public static final TaxStrategy COMPANY = new CompanyTaxStrategy();
public static final TaxStrategy TRUST = new TrustTaxStrategy();
private final TaxStrategy strategy;
private final double income;
public TaxPayer(TaxStrategy strategy, double income) {
this.strategy = strategy; this.income = income;
}
public double getIncome() {
return income;
}
public double extortCash() {
return strategy.extortCash(income);
}
}
public class ReceiverOfRevenue {
public static void main(String[] args) {
TaxPayer heinz = new TaxPayer(TaxPayer.EMPLOYEE, 50000);
TaxPayer maxsol = new TaxPayer(TaxPayer.COMPANY, 100000);
TaxPayer family = new TaxPayer(TaxPayer.TRUST, 30000);
System.out.println(heinz.extortCash());
System.out.println(maxsol.extortCash());
System.out.println(family.extortCash());
}
}
95 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
9. Template Method Pattern
In software engineering, the template method pattern is a design pattern. It is a so-called Behavioral
pattern, and is unrelated to C++ templates.
A template method defines the skeleton of an algorithm. The algorithm itself is made abstract, and the
subclasses of the method override the abstract methods to provide concrete behaviour.
First a class is created that provides the basic steps of an algorithm. These steps are implemented using
abstract methods. Later on, subclasses change the abstract methods to implement real actions. Thus the
general algorithm is saved in one place but the concrete steps may be changed by the subclasses.
Participants
q AbstractClass
o Defines abstract primitive operations that concrete subclasses define to implement steps of
an algorithm.
o Implements a template method defining the skeleton of an algorithm. The template method
calls primitive operations as well as operations defined in AbstractClass or those of other
objects.
q ConcreteClass
o Implements the primitive operations to carry out subclass-specific steps of the algorithm
96 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Example:
package example.behavioural.template;
import java.util.ArrayList;
import java.util.Iterator;
public class RunTemplateMethodPattern {
public static void main(String [] arguments){
System.out.println("Example for the Template Method pattern");
System.out.println("This code demonstrates how the template method can");
System.out.println(" be used to define a variable implementation for a");
System.out.println(" common operation. In this case, the ProjectItem");
System.out.println(" abstract class defines the method getCostEstimate,");
System.out.println(" which is a combination of the cost for time and");
System.out.println(" materials. The two concrete subclasses used here,");
System.out.println(" Task and Deliverable, have different methods of");
System.out.println(" providing a cost estimate.");
System.out.println("Creating a demo Task and Deliverable");
System.out.println();
Task primaryTask = new Task("Put a JVM on the moon", "Lunar mission as part of
the JavaSpace program ;)", 240.0, 100.0);
primaryTask.addProjectItem(new Task("Establish ground control", "", 1000.0,
10.0));
primaryTask.addProjectItem(new Task("Train the Javanaughts", "", 80.0,
30.0));
Deliverable deliverableOne = new Deliverable("Lunar landing module", "Ask the
local garage if they can make a few minor modifications to one of their cars", 2800,
40.0, 35.0);
System.out.println("Calculating the cost estimates using the Template Method,
getCostEstimate.");
System.out.println("Total cost estimate for: " + primaryTask);
System.out.println("\t" + primaryTask.getCostEstimate());
System.out.println();
System.out.println("Total cost estimate for: " + deliverableOne);
System.out.println("\t" + deliverableOne.getCostEstimate());
}
}
//AbstractClass containing Template Method
package example.behavioural.template;
abstract class ProjectItem {
private String name;
private String description;
private double rate;
public ProjectItem() {
}
97 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
public void setRate(double newRate) {
rate = newRate;
}
import java.util.ArrayList;
import java.util.Iterator;
public Task() {
}
98 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
}
public double getTaskTimeRequired() {
return taskTimeRequired;
}
public Iterator getProjectItemIterator() {
return projectItems.iterator();
}
public double getMaterialsCost() {
double totalCost = 0;
Iterator items = getProjectItemIterator();
while (items.hasNext()) {
totalCost += ((ProjectItem) items.next()).getMaterialsCost();
}
return totalCost;
}
public Deliverable() {
}
public Deliverable(String newName, String newDescription,
double newMaterialsCost, double newProductionTime, double newRate) {
super(newName, newDescription, newRate);
materialsCost = newMaterialsCost;
productionTime = newProductionTime;
}
public void setMaterialsCost(double newCost) {
materialsCost = newCost;
}
public void setProductionTime(double newTime) {
productionTime = newTime;
}
public double getMaterialsCost() {
return materialsCost;
}
public double getTimeRequired() {
return productionTime;
}
}
99 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
10. Structure of Visitor Pattern
In object-oriented programming and software engineering, the visitor design pattern is a way of separating
an algorithm from an object structure. A practical result of this separation is the ability to add new
operations to existing object structures without modifying those structures.
The idea is to use a structure of element classes, each of which has an accept method that takes a visitor
object as an argument. Visitor is an interface that has a visit() method for each element class. The accept()
method of an element class calls back the visit() method for its class. Separate concrete visitor classes can
then be written that perform some particular operations.
One of these visit() methods of a concrete visitor can be thought of as methods not of a single class, but
rather methods of a pair of classes: the concrete visitor and the particular element class. Thus the visitor
pattern simulates double dispatch in a conventional single-dispatch object-oriented language such as Java,
Smalltalk, and C++.
The visitor pattern also specifies how iteration occurs over the object structure. In the simplest version,
where each algorithm needs to iterate in the same way, the accept() method of a container element, in
addition to calling back the visit() method of the visitor, also passes the visitor object to the accept()
method of all its constituent child elements.
Because the Visitor object has one principal function (manifested in a plurality of specialized methods) and
that function is called visit(), the Visitor can be readily identified as a potential function object or functor.
Likewise, the accept() function can be identified as a function applicator, a mapper, which knows how to
traverse a particular type of object and apply a function to its elements.
100 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Structure of Visitor Pattern
Participants
q Visitor
o Declares a Visit operation for each class of ConcreteElement in the object structure. The
operation's name and signature identifies the class that sends the Visit request to the visitor.
That lets the visitor determine the concrete class of the element being visited. Then the
visitor can access the elements directly through its particular interface.
q ConcreteVisitor (IncomeVisitor, VacationVisitor)
o Implements each operation declared by Visitor. Each operation implements a fragment of
the algorithm defined for the corresponding class or object in the structure. ConcreteVisitor
provides the context for the algorithm and stores its local state. This state often accumulates
results during the traversal of the structure.
q Element
o Defines an Accept operation that takes a visitor as an argument.
q ConcreteElement
o Implements an Accept operation that takes a visitor as an argument.
q ObjectStructure
o Can enumerate its elements.
o May provide a high-level interface to allow the visitor to visit its elements.
o May either be a Composite (pattern) or a collection such as a list or a set.
101 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
Example:
package example.behavioural.visitor;
//Visitor Interface
interface Visitor {
void visit(Wheel wheel);
// Element Interface
interface Visitable {
public void accept(Visitor visitor);
}
// ConcreteElementA
class Wheel implements Visitable {
private String name;
Wheel(String name) {
this.name = name;
}
String getName() {
return this.name;
}
// ConcreteElementB
class Engine implements Visitable {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// ConcreteElementC
class Body implements Visitable {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// ObjectStructure
class Car implements Visitable {
private Engine engine = new Engine();
private Body body = new Body();
private Wheel[] wheels = { new Wheel("front left"),
new Wheel("front right"), new Wheel("back left"),
new Wheel("back right") };
102 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
visitor.visit(this);
engine.accept(visitor);
body.accept(visitor);
for (int i = 0; i < wheels.length; ++i)
wheels[i].accept(visitor);
}
}
// ConcreteVisitor1
class PrintVisitor implements Visitor {
public void visit(Wheel wheel) {
System.out.println("Visiting " + wheel.getName() + " wheel");
}
// ConcreteVisitor2
class WashingVisitor implements Visitor {
public void visit(Wheel wheel) {
System.out.println("Washing " + wheel.getName() + " wheel");
}
// Client
public class VisitorDemo {
static public void main(String[] args) {
Car car = new Car();
Visitor printVisitor = new PrintVisitor();
car.accept(printVisitor);
Visitor washVisitor = new WashingVisitor();
car.accept(washVisitor);
}
}
103 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
11. Interpreter Pattern
The Interpreter Pattern defines a grammatical representation for a language and an interpreter to interpret
the grammar. The best example you can get for this is Java itself, which is an interpreted language. It
converts the code written in English to a byte code format so as to make possible for all the operating
systems to understand it. This quality of it makes it platform independent.
Participants
q AbstractExpression
o Declares an abstract Interpret operation that is common to all nodes in the abstract syntax
tree.
q TerminalExpression
o Implements an Interpret operation associated with terminal symbols in the grammar.
o An instance is required for every terminal symbol in a sentence.
q NonterminalExpression
o One such class is required for every rule R ::= R1R2...Rn in the grammar.
o Maintains instance variables of type AbstractExpression for each of the symbols R1 through
Rn.
o Implements an Interpret operation for nonterminal symbols in the grammar. Interpret
typically calls itself recursively on the variables representing R1 through Rn.
q Context
o Contains information that is global to the interpreter.
104 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
q Client
o Builds (or is given) an abstract syntax tree representing a particular sentence in the language
that the grammar defines. The abstract syntax tree is assembled from instances of the
NonterminalExpression and TerminalExpression classes.
o Invokes the Interpret operation
Example 1:
package example.behavioural.interpreter;
import java.util.*;
interface Expression {
public void interpret(Stack<Integer> s);
}
class Parser {
private ArrayList<Expression> parseTree = new ArrayList<Expression>(); // only
public Parser(String s) {
for (String token : s.split(" ")) {
if (token.equals("+"))
parseTree.add(new TerminalExpression_Plus());
else if (token.equals("-"))
parseTree.add(new TerminalExpression_Minus());
// ...
else
parseTree.add(new TerminalExpression_Number(Integer
.valueOf(token)));
}
}
105 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
public int evaluate() {
Stack<Integer> context = new Stack<Integer>();
for (Expression e : parseTree)
e.interpret(context);
return context.pop();
}
}
import java.util.HashMap;
import java.util.Stack;
public Calculator() {
operators = new HashMap();
operators.put("+", "1");
operators.put("-", "1");
operators.put("/", "2");
operators.put("*", "2");
operators.put("(", "0");
}
107 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
pfExpr = pfExpr + tempStr;
tempStr = (String) s.pop();
}
tempStr = "";
}
// if the current character is an
// operator
if (isOperator(currChar)) {
if (s.isEmpty() == false) {
tempStr = (String) s.pop();
String strVal1 = (String) operators.get(tempStr);
int val1 = new Integer(strVal1).intValue();
String strVal2 = (String) operators.get(currChar);
int val2 = new Integer(strVal2).intValue();
while ((val1 >= val2)) {
pfExpr = pfExpr + tempStr;
val1 = -100;
if (s.isEmpty() == false) {
tempStr = (String) s.pop();
strVal1 = (String) operators.get(tempStr);
val1 = new Integer(strVal1).intValue();
}
}
if ((val1 < val2) && (val1 != -100))
s.push(tempStr);
}
s.push(currChar);
}// if
}// for
while (s.isEmpty() == false) {
tempStr = (String) s.pop();
pfExpr = pfExpr + tempStr;
}
return pfExpr;
}
interface Expression {
public int evaluate(Context c);
}
class Context {
private HashMap varList = new HashMap();
108 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
public Context() {
initialize();
}
public TerminalExpression(String v) {
var = v;
}
109 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T
}
}// AddExpression
110 | S u m i t A g r a w a l | J a v a A r c h i t e c t | M C C R e t a i l C O E | H C L T