Design Patterns (Riddhi Dutta)
Design Patterns (Riddhi Dutta)
CREATIONAL PATTERNS :
SINGLETON PATTERN :
In object-oriented programming, a singleton class is a class that can have only one object (an instance of the class)
at a time.
After first time, if we try to instantiate the Singleton class, the new variable also points to the first instance created. So
whatever modifications we do to any variable inside the class through any instance, it affects the variable of the single
instance created and is visible if we access that variable through any variable of that class type defined.
To design a singleton class:
class Mother
{
private String name;a
private static Mother m = null;
private Mother(String n)
{
name = n;
}
public Mother getMother(String n)
{
if(m==null)
m = new Mother(n);
return m;
}
}
For a child class there can be only one mother instance hence Mother class is a singleton class.
We keep the constructor private and make a getMother() method which will be called from
outside to instantiate a new Mother object. If an object of Mother class is already created before
that same instance will be returned else a new Mother object will be returned.
Factory method is a creational design pattern, i.e., related to object creation. In Factory pattern, we create object without
exposing the creation logic to client and the client use the same common interface to create new type of object.
Factory method creates the object and returns it to the client(one who calls the factory method) depending on the parameter
passed. So if we have to insert a new object type we will add code to the factory method and not in the client. The object
type is the concrete product and it’s base class is the product.
/**
* Product interface
*/
public interface GeometricShape {
void draw();
}
/**
* Concrete Product
*/
public class Line implements GeometricShape {
@Override
public void draw() {
System.out.println("Line Drawn.");
}
}
/**
* Concrete Product
*/
public class Rectangle implements GeometricShape {
@Override
public void draw() {
System.out.println("Rectangle is drawn.");
}
}
/**
* Concrete product
*/
public class Circle implements GeometricShape{
@Override
public void draw() {
System.out.println("Circle is drawn.");
}
}
Now, let's create a factory that provides the product (in this case, GeometricShape):
/**
* Concrete Product
*/
public abstract class ShapeFactory {
public static GeometricShape getShape(ShapeType name) {
GeometricShape shape = null;
switch (name) {
case LINE:
shape = new Line();
break;
case CIRCLE:
shape = new Circle();
break;
case RECTANGLE:
shape = new Rectangle();
break;
}
return shape;
}
}
The client for the application provides the name of the shape required as follow.
/**
* Client
*/
public class Application {
public static void main(String[] args) {
//requests for circle shape
GeometricShape circle = ShapeFactory.getShape(ShapeType.CIRCLE);
if (circle != null) {
circle.draw();
} else {
System.out.println("This shape can not be drawn.");
}
//requests non existent shape
GeometricShape triangle = ShapeFactory.getShape(ShapeType.TRIANGLE);
if (triangle != null) {
triangle.draw();
} else {
System.out.println("This shape can't be drawn");
}
}
}
Circle is drawn.
This shape can't be drawn
BUILDER PATTERN
Builder pattern aims to “Separate the construction of a complex object from its representation so that the same construction
process can create different representations.” It is used to construct a complex object step by step and the final step will
return the object. The process of constructing an object should be generic so that it can be used to create different
representations of the same object.
Below is the coded solution of problem we discussed above. This uses a additional class
UserBuilder which helps us in building desired User object with all mandatory attributes and
combination of optional attributes, without loosing the immutability.
@Override
public String toString() {
return "User: "+this.firstName+", "+this.lastName+", "+this.age+", "+this.phone+",
"+this.address;
}
public static class UserBuilder
{
private final String firstName;
private final String lastName;
private int age;
private String phone;
private String address;
System.out.println(user1);
System.out.println(user2);
System.out.println(user3);
}
Output:
Chain of Responsibility :
Chain of Responsibility is a behavioral design pattern that lets you pass requests along a chain of handlers. Upon
receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.
The Handler declares the interface, common for all concrete handlers. It usually contains just a single method for handling
requests, but sometimes it may also have another method for setting the next handler on the chain.
The Base Handler is an optional class where you can put the boilerplate code that’s common to all handler classes.
Usually, this class defines a field for storing a reference to the next handler. The clients can build a chain by passing a
handler to the constructor or setter of the previous handler. The class may also implement the default handling behavior: it
can pass execution to the next handler after checking for its existence.
method add(child) is
children.add(child)
child.container = this
method showHelp() is
if (modalHelpText != null)
// Show a modal window with the help text.
else
super.showHelp()
// ...same as above...
class Dialog extends Container is
field wikiPageURL: string
method showHelp() is
if (wikiPageURL != null)
// Open the wiki help page.
else
super.showHelp()
// Client code.
class Application is
// Every application configures the chain differently.
method createUI() is
dialog = new Dialog("Budget Reports")
dialog.wikiPageURL = "http://..."
panel = new Panel(0, 0, 400, 800)
panel.modalHelpText = "This panel does..."
ok = new Button(250, 760, 50, 20, "OK")
ok.tooltipText = "This is an OK button that..."
cancel = new Button(320, 760, 50, 20, "Cancel")
// ...
panel.add(ok)
panel.add(cancel)
dialog.add(panel)
Command :
● Encapsulate a request as an object, thereby letting you parametrize clients with different requests, queue or
log requests, and support undoable operations.
● Promote "invocation of a method on an object" to full object status
● An object-oriented callback
The client that creates a command is not the same client that executes it. This separation provides flexibility in the timing
and sequencing of commands. Materializing commands as objects means they can be passed, staged, shared, loaded in a
table, and otherwise instrumented or manipulated like any other object.
The client that creates a command is not the same client that executes it. This separation provides flexibility in the timing
and sequencing of commands. Materializing commands as objects means they can be passed, staged, shared, loaded in a
table, and otherwise instrumented or manipulated like any other object.
The Command pattern allows requests to be encapsulated as objects, thereby allowing clients to be parametrized
with different requests. The "check" at a diner is an example of a Command pattern. The waiter or waitress takes an
order or command from a customer and encapsulates that order by writing it on the check. The order is then queued
for a short order cook. Note that the pad of "checks" used by each waiter is not dependent on the menu, and
therefore they can support commands to cook many different items.
Check list
STRATEGY
● Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the
algorithm vary independently from the clients that use it.
● Capture the abstraction in an interface, bury implementation details in derived classes.
A Strategy defines a set of algorithms that can be used interchangeably. Modes of transportation to an airport is an example
of a Strategy. Several options exist such as driving one's own car, taking a taxi, an airport shuttle, a city bus, or a limousine
service. For some airports, subways and helicopters are also available as a mode of transportation to the airport. Any of
these modes of transportation will get a traveler to the airport, and they can be used interchangeably. The traveler must
chose the Strategy based on trade-offs between cost, convenience, and time.
interface Strategy {
void solve();
}
// 2. Bury implementation
@SuppressWarnings("ALL")
abstract class StrategySolution implements Strategy {
// 3. Template Method
public void solve() {
start();
while (nextTry() && !isSolution()) {}
stop();
}
// 2. Bury implementation
abstract class StrategySearch implements Strategy {
// 3. Template Method
public void solve() {
while (true) {
preProcess();
if (search()) {
break;
}
postProcess();
}
}
@SuppressWarnings("ALL")
class BAR extends StrategySearch {
private int state = 1;
Output
start nextTry-1 isSolution-false nextTry-2 isSolution-true stop
preProcess search-1 postProcess preProcess search-2
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.
● Wrap an existing class with a new interface.
● Impedance match an old component to a new system
Below, a legacy Rectangle component's display() method expects to receive "x, y, w, h" parameters. But the client wants to
pass "upper left x and y" and "lower right x and y". This incongruity can be reconciled by adding an additional level of
indirection – i.e. an Adapter object.
The Adapter could also be thought of as a "wrapper".
class SquarePeg {
private double width;
/* The NEW */
class RoundHole {
private final int radius;
// Design a "wrapper" class that can "impedance match" the old to the new
class SquarePegAdapter {
// The adapter/wrapper class "has a" instance of the legacy class
private final SquarePeg squarePeg;
public SquarePegAdapter(double w) {
squarePeg = new SquarePeg(w);
}
Decorator : -
● Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to
subclassing for extending functionality.
● Client-specified embellishment of a core object by recursively wrapping it.
● Wrapping a gift, putting it in a box, and wrapping the box.
The client is always interested in CoreFunctionality.doThis(). The client may, or may not, be interested in OptionalOne.doThis()
and OptionalTwo.doThis(). Each of these classes always delegate to the Decorator base class, and that class always
delegates to the contained "wrappee" object.
Before
class A {
public void doIt() {
System.out.print('A');
}
}
After
interface I {
void doIt();
}
class A implements I {
public void doIt() {
System.out.print('A');
}
}
class X extends D {
public X(I inner) {
super(inner);
}
class Y extends D {
public Y(I inner) {
super(inner);
}
class Z extends D {
public Z(I inner) {
super(inner);
}
Output
AX AXY AXYZ