Java Programming/Design Patterns
![]() |
A Wikibookian suggests that Computer Science Design Patterns be merged into this book or chapter. Discuss whether or not this merger should happen on the discussion page. |
A design pattern is not a finished design, it is a description of a solution to a common problem. A design pattern can be reused in multiple applications, and that is the main advantage of using it. It can also be seen as a template for how to solve a problem that can occur in many different situations and/or applications. It is not code reuse as it usually does not specify code, but code can be easily created from a design pattern. Object-oriented design patterns typically show relationships and interactions between classes or objects, without specifying the final application classes or objects that are involved.
Each design pattern consist of the following part:
- Problem/requirement
- To create a design pattern, we need to go through a mini analysis design and may be coding to test out the solution. This section state the requirements the problem we want to solve. This is usually a common problem that will occur in more than one application.
- Forces
- This section state the technological boundaries, that helps and guides the creation of the solution.
- Solution
- This section describes how to write the code to solve the above problem. This is the design part of the design pattern. It may contain class diagrams, sequence diagrams, and or whatever is needed to describe how to code the solution.
A design pattern can be considered as block that can be placed in your design document, and you have to implement the design pattern with your application.
Using design patterns speeds up your design and helps to communicate your design to other team members.
Contents |
[edit] Creational Patterns
[edit] Builder
Separate the construction of a complex object from its representation so that the same construction process can create different representations. ok
[edit] Factory Method
- Problem
- We want to decide at run time what object is to be created based on some configuration or application parameter. When we write the code we do not know what class should be instantiated.
- Solution
- Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
- Java Example
- Abstract creator
- Interface to create the Product.
package mypkg; import java.awt.image.BufferedImage; import java.io.IOException; /** * * @author imad.aydaroos */ public interface PhotoReader { public BufferedImage getImage()throws IOException; }
- Concreate creator
- a class to create specific Product.
package mypkg; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Iterator; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; /** * * @author imad.aydaroos */ public class JPEGReader implements PhotoReader { ImageReader reader; File jpegFile; ImageInputStream iis; public JPEGReader(String filePath)throws IOException{ jpegFile = new File(filePath); iis = ImageIO.createImageInputStream(jpegFile); Iterator readers = ImageIO.getImageReadersByFormatName("jpg"); reader = (ImageReader)readers.next(); this.reader.setInput(iis, true); } public BufferedImage getImage()throws IOException{ return reader.read(0); }
- Factory class
- a class to return a specific concreate creator at runtime to create the product .
package mypkg; import java.io.IOException; /** * * @author imad.aydaroos */ public class PhotoReaderFactory { enum Mimi { jpg,JPG, gif, GIF, bmp, BMP, png, PNG }; public static PhotoReader getPhotoReader(String filePath) { String suffix = getFileSuffix(filePath); PhotoReader reader = null; try{ switch (Mimi.valueOf(suffix)){ case jpg : reader = new JPEGReader(filePath); break; case JPG : reader = new JPEGReader(filePath); break; case gif : reader = new GIFReader(filePath); break; case GIF : reader = new GIFReader(filePath); break; case bmp : reader = new BMPReader(filePath); break; case BMP : reader = new BMPReader(filePath); break; case png : reader = new PNGReader(filePath); break; case PNG : reader = new PNGReader(filePath); break; default : break; } }catch(IOException io){ io.printStackTrace(); } return reader; } private static String getFileSuffix(String filePath) { String[] stringArray = filePath.split("\\."); return stringArray[stringArray.length - 1]; } }
[edit] Abstract Factory
Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
[edit] Prototype
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
[edit] Singleton
The term Singleton refers to an object that can be instantiated only once.
Use the Singleton Design pattern if:
- You need global access to a resource, like logging ...
- You need only one instance of a utility class, do not want to create lots of objects.
- Refresh Java object creation
In programming languages like Java, you have to create an instance of an object type (commonly called a Class) to use it throughout the code. Let's take for example this code:
Animal dog; // Declaring the object type dog = new Animal(); // Instantiating an object
This can also be written in a single line to save space.
Animal dog = new Animal(); // Both declaring and instantiating
At times, you need more than one instance of the same object type. You can create multiple instances of the same object type. Take for instance:
Animal dog = new Animal(); Animal cat = new Animal();
Now that I have two instances of the same object type, I can use both dog
and cat
instances separately in my program. Any changes to dog
would not effect the cat
instance because both of them have been created in separate memory spaces. To see whether these objects actually are different we do something like this:
System.out.println( (dog == cat) ); // output: false
The code returns false
because both the objects are different. Contrary to this behavior, the Singleton behaves differently. A Singleton object type can not be instantiated yet you can obtain an instance of the object type. Let us create a normal object using Java.
class NormalObject { public NormalObject() { } }
What we have done here is that we have created a class (object type) to identify our object. Within the parenthesis of the class is a single method with the same name as that of the class (methods can be identified by the usage of brackets at the end of their names). Methods that have the same name as that of the class and that do not have a return type are called Constructors in OOP syntax. To create an instance of the class, the code can not be much simpler.
class TestHarness { public static void main(String[] args) { NormalObject object = new NormalObject(); } }
Note that to encourage the instantiation of this object, the constructor is called. The constructor as in this case can be called outside the class paranthesis and into another class definition because it is declared a public accessor while creating the Constructor in the above example.
- Creating singleton object
Now we will create the Singleton object. You just have to change one thing to adhere to the Singleton design pattern: Make your Constructor's accessor private.
class SingletonObject { private SingletonObject() { } }
Notice the constructor's accessor. This time around it has been declared private. Just by changing it to private, you have applied a great change to your object type. Now you can not instantiate the object type. Go ahead try out the following code.
class TestHarness { public static void main(String[] args) { SingletonObject object = new SingletonObject(); } }
The code returns an error because private class members can not be accessed from outside the class itself and in another class. This way you have disabled the instantiation process for an object type. However, you have to find a way of obtaining an instance of the object type. Let's do some changes here.
class SingletonObject { private static SingletonObject object; private SingletonObject() { //Instanciate the object. } public static SingletonObject getInstance() { if (object == null) { object = new SingletonObject(); // Create the object for the first and last time } return object; } }
The changes involve adding a static class member called object
and a public static
method that can be accessible outside the scope of the class by using the name of the Class. To see how we can obtain the instance, lets code:
class TestHarness { public static void main(String[] args) { SingletonObject object = SingletonObject.getInstance(); } }
This way you control the creation of objects derived from your class. But we have still not unearthed the final and interesting part of the whole process. Try creating multiple instances and see what happens.
class TestHarness { public static void main(String[] args) { SingletonObject object1 = SingletonObject.getInstance(); SingletonObject object2 = SingletonObject.getInstance(); } }
Unlike multiple instances of normal object types, multiple instances of a Singleton are all actually the same object instance. To validate the concept in Java, we try:
System.out.println( (object1 == object2) ); // output: true
The code returns true
because both object declarations are actually refering to the same object. So, in summarizing the whole concept, a Singleton can be defined as an object that can not be instantiated more than once. Typically it is obtained using a static custom implementation.
In some applications, it is appropriate to enforce a single instance of an object, for example: window managers, print spoolers, database access, and filesystems
[edit] Singleton & Multi Threading
Java uses multi threading concept, to run/execute any program. Consider the class SingletonObject discussed above. Call to the method getInstance() by more than one thread at any point of time might create two instances of SingletonObject thus defeating the whole purpose of creating the singleton pattern. To make singelton thread safe, we have three options:
1. Synchronize the method getInstance, which would look like:
// --- Only one thread can enter and stay in this method at a time --- public synchronized static Singleton getInstance() { if ( instance == null ) { instance = new Singleton(); } return instance; }
Synchronizing the method guarantees that a call to the method cannot be interrupted. The problem with the above code is that 'synchronization' is expensive. So practically the above code should neve be used.
2. Another approach would be to create a singleton instance as shown below:
class SingletonObject { public final static SingletonObject object; private static String lockObj = "Lock"; // -- Use for locking -- private SingletonObject() { //Exists Just to avoid instantiation. } public static SingletonObject getInstance() { if ( object != null ) { return object; } else { // --- Start a synchronized block, only one thread can enter and stay in the block one at a time -- synchronized(lockObj) { if ( object == null ) { object = new SingletonObject(); } } // --- End of synchronized block --- return object; } } }
The above code will be much faster; once the singleton instance is created no syncronization is needed, it just returns the same instance reference.
3. Use static initialization block to create the instance. The JVM makes sure that the static block is executed once when the class is loaded.
class SingletonObject { public final static SingletonObject object; static { ... object = new SingletonObject(); } private SingletonObject() { //Exists Just to avoid instantiation. } public static SingletonObject getInstance() { return object; } }
[edit] Structural Patterns
[edit] Adapter
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
[edit] Bridge
The Bridge Pattern is used to separate out the interface from its implementation. Doing this gives the flexibility so that both can vary independently.
[edit] Composite
Components that are individual objects and also can be collection of objects. A Composite pattern can represent both the conditions. In this pattern, one can develop tree structures for representing part-whole hierarchies.
[edit] Decorator
The decorator pattern helps to add behavior or responsibilities to an object. This is also called “Wrapper”.
[edit] Facade
A Facade pattern hides the complexities of the system and provides an interface to the client from where the client can access the system.
Dividing a system into subsystems helps reduce complexity. We need to minimize the communication and dependencies between subsystems. For this, we introduce a facade object that provides a single, simplified interface to the more general facilities of a subsystem.
[edit] Flyweight
It is 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 a program is a candidate for using Flyweights, consider whether it is possible to remove some data from the class and make it extrinsic.
[edit] Proxy
It is used when you need to represent a complex with a simpler one. If creation of object is expensive, its creation can be postponed till the very need arises and till then, a simple object can represent it. This simple object is called the “Proxy” for the complex object.
[edit] Behavioral Patterns
[edit] Chain of Responsibility
[edit] Command
[edit] Scope
Object
[edit] Purpose
Behavioural
[edit] Intent
encapsulate the request for a service as an object
[edit] Applicability
- to parameterize objects with an action to perform
- to specify, queue, and execute requests at different times
- for a history of requests
- for multilevel undo/redo
[edit] Structure
[edit] Consequences
- + abstracts executor of a service
- + supports arbitrary-level undo-redo
- + composition yields macro-commands
- - might result in lots of trivial command subclasses
[edit] Implementation
- copying a command before putting it on a history list
- handling hysteresis
- supporting transactions
Command pattern is an Object behavioural pattern that decouples sender and receiver. It can also be thought as an object oriented equivalent of call back method.
Call Back: It is a function that is registered to be called at later point of time based on user actions.
public interface Command{ public int execute(int a, int b); } public class AddCommand implements Command{ public int execute(int a, int b){ return a + b; } } public class MultCommand implements Command{ public int execute(int a, int b){ return a * b; } } public class TestCommand{ public static void main(String a[]){ Command add = new AddCommand(); add.execute(1,2); // returns 3 Command multiply = new MultCommand(); multiply.execute(2,3); // returns 6 } }
In the above example, it can be noted that the command pattern decouples the object that invokes the operation from the ones having the knowledge to perform it. --Peer Mohamed P U 11:53, 1 March 2006 (UTC)
[edit] Command in Java
Menus and buttons provide a classic example of the need for the COMMAND pattern. When you add a menu to an application, you have to configure the menu with words that describe actions that the user can choose, such as Save and Open. Similarly for a button. You also have to configure the menu or button so that it can take action, calling a method in response to a user's click. However, JMenuItem or JButton class has no way of knowing what action to perform when an item or button is selected. In the following example we use the same Action for both a menu item and a button saving us from having to write the same code twice.
Action actionOpen = new AbstractAction("Open...", iconOpen) { public void actionPerformed(ActionEvent e) { ... // open a file } } JMenu mFile = new JMenu("File"); JMenuItem item = mFile.add(actionOpen); // use the same action for both a menu item ... JToolBar m_toolBar = new JToolBar(); JButton bOpen = new JButton(actionOpen); // ... and a button m_toolBar.add(bOpen);
Java Swing applications commonly apply the MEDIATOR pattern, registering a single object to receive all GUI events. This object mediates the interaction of the components and translates user input into commands for business domain objects
[edit] Undo in Java
Swing provides for Undo/Redo functionality.
import javax.swing.undo.*; UndoManager undoManager = new UndoManager(); Action undoAction, redoAction; undoAction = new AbstractAction("Undo", new ImageIcon("edit_undo.gif")) { public void actionPerformed(ActionEvent e) { try { undoManager.undo(); // undoManager.redo(); } catch (CannotUndoException ex) { System.err.println("Unable to undo: " + ex); } updateUndo(); } }; // same for Redo protected void updateUndo() { if(undo.canUndo()) { undoAction.setEnabled(true); undoAction.putValue(Action.NAME, undo.getUndoPresentationName()); } else { undoAction.setEnabled(false); undoAction.putValue(Action.NAME, "Undo"); } if(undo.canRedo()) { redoAction.setEnabled(true); redoAction.putValue(Action.NAME, undo.getRedoPresentationName()); } else { redoAction.setEnabled(false); redoAction.putValue(Action.NAME, "Redo"); } }
[edit] Interpreter
Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
[edit] Iterator
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
[edit] Mediator
Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently
[edit] Memento / Serialize
Persisting object is a memento Pattern.
[edit] Observer
[edit] Scope
Object
[edit] Purpose
Behavioural
[edit] Intent
define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically
[edit] Applicability
- when an abstraction has two aspects, one dependent on the other
- when a change to one object requires changing others, and you don't know how many objects need to be changed
- when an object should notify other objects without making assumptions about who these objects are
[edit] Structure
[edit] Consequences
- + modularity: subject and observers may vary independently
- + extensibility: can define and add any number of observers
- + customizability: different observers provide different views of subject
- - unexpected updates: observers don't know about each other
- - update overhead: might need hints
[edit] Implementation
- subject-observer mapping
- dangling references
- avoiding observer-specific update protocols: the push and pull models
- registering modifications of interest explicitly
[edit] Related pattern
- Singleton[[1]], is used to make observable object unique and accessible globally.
- Mediator[[2]], is used to encapsulate updated objects
[edit] Description
- Problem
- In one place or many places in the application we need to be aware about a system event or an application state change. We'd like to have a standard way of subscribing to listening for system events and a standard way of notifying the interested parties. The notification should be automated after an interested party subscribed to the system event or application state change. There should be a way to unsubscribe, too.
- Forces
- Observers and observables probably should be represented by objects. The observer objects will be notified by the observable objects.
- Note
- The Java JDK has a implementation of this pattern.
- Application in Graphical User Interfaces such as in the AWK toolkit, Swing etc. In Swing, whenever a user clicks a button or adjusts a slider, many objects in the application may need to react to the change. Swing refers to interested clients (observers) as "listeners" and lets you register as many listeners as you like to be notified of a component's events.
MVC is more M(VC) in Swing, i.e. View and Controller are tightly coupled; Swing does not divide Views from Controllers. MVC supports n-tier development, i.e. loosely coupled layers (see below) that can change independently and that may even execute on different machines.
- Solution
- After subscribing the listening objects will be notified by a way of method call.
- Loose coupling
- when two objects are loosely coupled, they can interact, but they have very little knowledge of each other. Strive for loosely coupled designs between objects that interact.
- The only thing that Subject knows about an observer is that it implements a certain interface
- We can add new observers at any time
- We never need to modify the subject to add new types of observers
- We can reuse subjects or observers independently of each other
- Changes to either the subject or an observer will not affect the other
// Observer pattern -- Structural example // @since JDK 5.0 import java.util.ArrayList; // "Subject" abstract class Subject { // Fields private ArrayList<Observer> observers = new ArrayList<Observer>(); // Methods public void attach(Observer observer){ observers.add(observer); } public void detach(Observer observer) { observers.remove(observer); } public void notifyObservers() { for (Observer o : observers) o.update(); } } // "ConcreteSubject" class ConcreteSubject extends Subject { // Fields private String subjectState; // Properties public String getSubjectState() { return subjectState; } public void setSubjectState (String value) { subjectState = value; } } // "Observer" abstract class Observer { // Methods abstract public void update(); } // "ConcreteObserver" class ConcreteObserver extends Observer{ // Fields private String name; private String observerState; private ConcreteSubject subject; // Constructors public ConcreteObserver (ConcreteSubject subject, String name) { this.subject = subject; this.name = name; //subject.attach(this); } // Methods public void update() { observerState = subject.getSubjectState(); System.out.printf("Observer %s's new state is %s\n", name, observerState ); } } // Client test public class Client { public static void main(String[] args) { // Configure Observer structure ConcreteSubject s = new ConcreteSubject(); s.attach(new ConcreteObserver(s,"A")); s.attach(new ConcreteObserver(s,"B")); s.attach(new ConcreteObserver(s,"C")); // Change subject and notify observers s.setSubjectState("NEW"); s.notifyObservers(); } }
[edit] Observer in Java
Java, however, has built in support for the Observer pattern. All one has to do is extend java.util.Observable
(the Subject) and tell it when to notify the java.util.Observer
s. The API does the rest for you. You may use either push or pull style of updating your observers.
java.util.Observable
is a class while java.util.Observer
is an interface
public void setValue(double value) { this.value = value; setChanged(); notifyObservers(); }
Note that you have to call setChanged()
so that the Observable
code will broadcast the change. The notifyObservers()
method calls the update()
method of each registered observer. The update()
method is a requirement for implementers of the Observer
Interface.
// Observer pattern -- Structural example import java.util.Observable; import java.util.Observer; // "Subject" class ConcreteSubject extends Observable { // Fields private String subjectState; // Methods public void dataChanged() { setChanged(); notifyObservers(); // use the pull method } // Properties public String getSubjectState() { return subjectState; } public void setSubjectState(String value) { subjectState = value; dataChanged(); } } // "ConcreteObserver" import java.util.Observable; import java.util.Observer; class ConcreteObserver implements Observer { // Fields private String name; private String observerState; private Observable subject; // Constructors public ConcreteObserver (Observable subject, String name) { this.subject = subject; this.name = name; subject.addObserver(this); } // Methods public void update(Observable subject, Object arg) { if (subject instanceof ConcreteSubject) { ConcreteSubject subj = (ConcreteSubject)subject; observerState = subject.getSubjectState(); System.out.printf("Observer %s's new state is %s\n", name, observerState ); } } } // Client test public class Client { public static void main(String[] args) { // Configure Observer structure ConcreteSubject s = new ConcreteSubject(); new ConcreteObserver(s,"A"); new ConcreteObserver(s,"B"); new ConcreteObserver(s,"C"); // Change subject and notify observers s.setSubjectState("NEW"); } }
The Observer pattern is used extensively in Java. E.g. in the following piece of code
button
is the SubjectMyListener
is the ObserveractionPerformed()
is the equivalent toupdate()
JButton button = new JButton ("Click me!"); button.addActionListener(new MyListener()); class MyListener implements ActionListener { public void actionPerformed(ActionEvent event) { ... } }
Another example is the PropertyChangeSupport
. The Component
class uses a PropertyChangeSupport
object to let interested observers register for notification of changes in the properties of labels, panels, and other GUI components.
Can you find the Subject
, Observer
and update()
in the above class diagram?
Component
is the SubjectPropertyChangeListener
is the ObserverpropertyChange()
is the equivalent toupdate()
The Java implementation of the Observer pattern has pros and cons:
Pros
- It hides many of the details of the Observer pattern
- It can be used both pull and push ways.
Cons
- Because
Observable
is a class, you have to subclass it; you can’t add on theObservable
behaviour to an existing class that subclasses another superclass (fails the programming to interfaces principle) - Because
setChanged()
is protected, you can’t favour composition over inheritance. - If you can’t subclass
Observable
, then use delegation, i.e. provide your class with an Observable object and have your class forward key method calls to it.
[edit] State
[edit] Strategy
[edit] Scope
Object
[edit] Purpose
Behavioural
[edit] Intent
define a family of algorithms, encapsulate each one, and make them interchangeable to let clients and algorithms vary independently from the clients using it
[edit] Applicability
- when an object should be configurable with one of several algorithms,
- and all algorithms can be encapsulated,
- and one interface covers all encapsulations
[edit] Structure
[edit] Consequences
- + greater flexibility, reuse
- + can change algorithms dynamically
- - strategy creation & communication overhead
- - inflexible Strategy interface
[edit] Implementation
- exchanging information between a Strategy and its context
- static strategy selection via templates
[edit] Related patterns
- State[[3]], can activate several states, whereas a strategy can only activate one of the algorithms.
- Flyweight[[4]], provides a shared object that can be used in multiple contexts simultaneously, whereas a strategy focuses on one context.
- Decorator[[5]], changes the skin of an object, whereas a strategy changes the guts of an object.
- Composite[[6]], is used in combination with a strategy to improve efficiency.
[edit] Description
Suppose that you work for a company that builds a strategy game. Let assume that you 've come up with the following hierarchy of classes. All characters are able to walk, and there is also a method to render them on screen. The superclass takes care of the implementation of walk()
method, while each subclass provides its own implementation of display()
since each character looks different.
A new requirement arrives that the characters need to fight, too. Simple job you say; just add a fight()
method to Character
superclass. But, wait a moment; what about Workers? They cannot fight!
Well, one could think that you could simply override fight()
method in Worker
subclass to just do nothing.
class Worker { .... void fight() { // do nothing } .... }
But what if in the future there is a need for a Guard
class that can fight but shouldn’t walk? We need a cleaner solution. What about taking out the fight and walk behaviours from the superclass to an interface? That way, only the characters that are supposed to walk should implement the Walkable interface and only those characters that are supposed to fight should implement the Fightable
interface.
Well, this is another way to say for duplicate code. What if you need to make a small change to the fight behaviour? You would need to modify all the classes. At this point we should put down three design principles to follow in our application development:
- Identify the aspects of your application that vary and separate them from what stays the same. Take what varies and “encapsulate” it so it won’t affect the rest of your code.
- Program to an interface not to an implementation.
- Favour composition over inheritance.
So, let's apply the 1st design principle. Pull out fight and walk behaviour to different classes. And to apply the 2nd design principle as well, we have to pull out these behaviours to interfaces. Hence, we create a new WeaponBehaviour interface to deal with fight behaviour, and similarly a WalkBehaviour interface to deal with walk behaviour.
Character
s’ behaviours live in separate classes that implement a particular behaviour interface. That way, the Character
classes don’t need to know any of the implementation details for their own behaviours. In addition, we no more rely on an implementation but on an interface. Other types of objects can use these behaviours, too, because they 're not hidden inside our Character
class. And we can add new behaviours without modifying any of the existing ones or touching our character classes. So now, all we have to do is have our Character
class delegate all behaviour information to the two behaviour interfaces (so here comes the 3rd design principle). We do that by adding two instance variables to Character
, weapon
and walk
.
public abstract class Character { private WeaponBehaviour weapon; private WalkBehaviour walk; public void fight() { weapon.useWeapon(); // delegation of fight behaviour } public void setWeapon(WeaponBehaviour w){ weapon = w; } ... abstract void display(); }
Each character object will set these variables polymorphically to reference the specific behaviour type it would like at runtime.
public class Knight extends Character { public Knight() { weapon = new SwordBehaviour(); walk = new GallopBehaviour(); } public void display() { ... } }
Think of these behaviours as families of algorithms. So, composition gives you a lot of flexibility. Not only does it let you encapsulate a family of algorithms into their own set of classes, but it also lets you change behaviour at runtime as long as the object you are composing with, implements the correct behaviour interface.