Adapter Pattern tutorial with real world example

Adapter Pattern is a structural Design Pattern. An Adapter converts the interface of a class into another interface clients expect. An Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

When To Use Adapter Design Pattern:

  • We can not change the library interface(code), since we may not have its source code. Even if we did have the source code, we probably should not change the library for each domain-specific application.
  • Sometimes a toolkit or class library can not be used because its interface is incompatible with the interface required by an application.
  • Want to create a reusable class that cooperates with unrelated classes with incompatible interfaces.

Real Life Example of Adapter Pattern:
suppose I am a Programming Teacher, and I have two types of students in my class, the American students and the Brazilians students, since my Brazilians students don’t understand English, i have to have a transla-tor that will translate my lectures to my Brazilian students.

In this example, a Student class will be the Target, the translator will be the Adapter, and the Brazilians stu-dents will be the Adaptee, like the class diagram below:

Below is the example code:


import java.util.ArrayList;
import java.util.List;

// The Teacher Class
public class Teacher {

    List<Student> listStudent;

    public Teacher() {
	listStudent = new ArrayList<Student>();
    }

    public void teachStudents() {
	for (Student student : listStudent) {
	    student.learnLessonInEnglish();
	}
    }
}
// The Student Class
public abstract class Student {

    public abstract void learnLessonInEnglish();
}
// The Translator Class
public class Translator extends Student {

    BrazilianStudent brazilianStudent;

    public Translator(BrazilianStudent brazilianStudent) {
	super();
	this.brazilianStudent = brazilianStudent;
    }

    @Override
    public void learnLessonInEnglish() {
	// TODO Auto-generated method stub
	System.out.println("Translate to portuguese");
	brazilianStudent.learnLessonInPortuguese();
    }
}
// The AmericanStudent Class
public class AmericanStudent extends Student {

    @Override
    public void learnLessonInEnglish() {
	// TODO Auto-generated method stub
	System.out.println("Learning in english");
    }
}
// The BrazilianStudent Class
public class BrazilianStudent {
    public void learnLessonInPortuguese() {
	System.out.println("Learn in portuguese");
    }
}

Bridge Pattern in java with real world example

The Bridge Pattern is a structural design pattern which is meant to “decouple an abstraction from its implementation so that the two can vary independently”. The bridge uses encapsulation, aggregation, and can use inheritance to separate responsibilities into different classes.

The normal method of dealing with an abstraction having several implementations is through inheritance. However, this permanently binds the implementation to the abstraction. This is not always flexible enough. You may want to modify or extend the abstraction or implementations independently. The Bridge Pattern decouples an abstraction from its implementation.

When To Use Bridge Pattern:

  • You want to hide implementation details (changes) from clients.
  • Selection or switching of implementation is at run-time rather than design time.
  • Abstraction and implementation should both be extensible by subclassing.
  • You want to share an implementation among multiple objects and this should be hidden from the client.

Real Life Example: In real life scenario bridge pattern is used for writing persistence APIs. While writing application layer developer want to fetch information from persistence system (E.g. Database or File System). In this scenario there are two interfaces:

1st at Application layer – Where end user/client is routed.
2nd at Persistance layer – Interface which encapsulates logic to persist/fetch information

To have flexible design one would like to decouple application layer from persistence API. I.e. I want to have flexibility to use any persistence system (Database, File System, via JMS e.t.c). Below sample example explains bridge design pattern to improve extensibility.

Class Diagram:

Code:
Abstraction Interface:  Persistence

package com.thecafetechno.structural.bridge.application;

import com.thecafetechno.structural.bridge.apptopersisterbridge.PersistenceImplementor;

/**
 * This is abstraction Interface.
 *
 */

public abstract class Persistence {
    private PersistenceImplementor persistanceImplementor = null;

    /**
     * Constructor.
     *
     * @param implementer
     */
    public Persistence(PersistenceImplementor implementer) {
	this.persistanceImplementor = implementer;
    }

    /**
     * Persist Object.
     *
     * @param object
     * @return returns objectID
     */
    public abstract String persist(Object object);

    /**
     * Find record by primary key.
     *
     * @param objectId
     * @return persisted Object
     */
    public abstract Object findById(String objectId);

    /**
     * Delete record by primary key.
     *
     * @param id
     */
    public abstract void deleteById(String id);

    /**
     * Getter for PersistenceImplementor.
     *
     * @return PersistenceImplementor
     */
    public PersistenceImplementor getPersistanceImplementor() {
	return persistanceImplementor;
    }

    /**
     * Setter for PersistenceImplementor.
     *
     * @param persistanceImplementor
     *            Input persistence implementor
     */
    public void setPersistanceImplementor(
	    PersistenceImplementor persistanceImplementor) {
	this.persistanceImplementor = persistanceImplementor;
    }
}

Strategy Pattern in Java with real world example

Strategy Design Pattern defines a family of algorithms, encapsulates each one and makes them interchangeable. Subclasses decide how to implement steps in an algorithm.

Strategy Pattern is a behavioural design pattern. Often developer gets confused with Template Pattern and Starategy Pattern. For explanation I will use same example we used in Template with some changes in requirement. Let’s understand the Startegy pattern before jumping to difference between Teamplate Pattern and Strategy Pattern.

When To Use Strategy Design Pattern:

  1. When you want different variants of an algorithm.
  2. When many related classes differ only in their behavior.
  3. When a class defines many behaviors, and these appear as multiple conditional statements in its operations. Instead of many conditionals statements, move related conditional branches into their own Strategy class.
  4. When an algorithm uses data that clients shouldn’t know about. Use the Strategy Pattern to avoid exposing complex and algorithm-specific data structures.

Real World Example of Strategy Pattern:

  • Swing GUI Text components
  • Java AWT

Advantages of Strategy Pattern:

  • It provides an alternative to sub-classing the Context class to get a variety of algorithms or behaviors.
  • It eliminates large number of conditional statements.

Problems With Strategy Pattern:

  • Increases the number of objects.
  • All algorithms must use the same Strategy interface

An Example:
We want to develop a system to process flat files for: Stock and Derivatives.

Requirement:

  • Validate File type/format against system configuration
  • Stock or Derivative data can be stored in database or content repository (e.g. XML)
  • File can be routed to third party system Capital IQ(via SOAP) or other customers (e.g. JMS)
  • Investment Bank can do the below action:

City Bank: validate, store (Repo) and route to Capital IQ
ICICI Bank: validate, store data(database) and route to Capital IQ
Axis Bank: validate, store data and route to other customer

Decorator Pattern in java with real world example

When To Use Decorator Design Pattern:
1. When you want to add responsibilities to individual objects dynamically without affecting other objects.
2. When extension by sub classing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for sub classing.

Real Life Examples of Decorator Pattern:
Java Swing components E.g. JComponent (extends Container)
Java I/O classes

Buffered Stream – adds buffering for the stream
Data Stream – allows I/O of primitive Java data types
Pushback Stream – allows undo operation

Example: Explosion of subclasses
Suppose we have a TextView GUI component and we want to add different kinds of borders and scrollbars to it. Suppose we have three types of borders: Plain, 3D, Fancy and two types of scrollbars: Horizontal, Vertical

Case Study:
Write a decorator that converts all uppercase characters to lowercase in the input stream.

Requirements:
Convert all alphabet to lower case while reading file. E.g. If Input read “I know the Decorator Pattern therefore I RULE!” then decorator converts this to “i know the decorator pattern therefore i rule!”

Explanation:

  • Abstract Component – InputStream
  • Concrete Components – FileInputStream, StringBufferInputStream, ByteArrayInputStream
  • Abstract Decorator – FilterInputStream
  • Concrete Decorator – InputStreamDecorator

Note:

  • Abstract Decorator extends Abstract Component.
  • Abstract Decorator (FilterInputStream) Decorators implement the same interface or abstract class as the component they are going to decorate.
  • The Concrete Component (FileInputStream) is the object we’re going to dynamically add new behavior to. It extends Component.

Class Diagram:

  • Decorators have the same super type as the objects they decorate.
  • You can use one or more decorators to wrap an object.
  • Given that the decorator has the same super type as the object it decorates, we can pass around a decorated object in place of the original (wrapped) object.
  • The decorator adds its own behavior either before and/or after delegating to the object it decorates to do the rest of the job.
  • Objects can be decorated at any time, so we can decorate objects dynamically at runtime with as many decorators as we like.

Code:
Abstract Component – InputStream – Refer Java API Source
Concrete Components – FileInputStream – Refer Java API Source
Abstract Decorator – FilterInputStream – Refer Java API Source
Concrete Decorator Class: InputStreamDecorator

package com.thecafetechno.structural.decoratorPattern;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * InputStreamDecorator decorate IO class to convert all upper case characters
 * to lower case in the input stream.
 * 
 * 1) Extend the abstract decorator for all Input Stream. Note that
 * FilterInputStream extends InputStream
 * 
 * 2) Composition – InputStream via contructor.
 * 
 * 3) Implement two read method within InputStream.
 * 
 * Note: The Decorator Pattern attach additional responsibilities to an object
 * dynamically.
 * 
 * A) Decorators provide a flexible alternative to subclassing for extending
 * functionality. Inheritance is one form of extension, but not necessarily the
 * best way to achieve flexibility in our designs. Composition and delegation
 * can often be used to add new behaviors at runtime <br>
 * 
 * B) Decorators have the same super type as the objects they decorate
 * 
 * C) The decorator adds its own behavior either before and/or after delegating
 * to the object it decorates to do the rest of the job.
 * 
 * 
 */
public class InputStreamDecorator extends FilterInputStream {

    protected InputStreamDecorator(InputStream in) {
	super(in);
    }

    public int read() throws IOException {
	int c = super.read();
	return (c == -1 ? c : Character.toLowerCase((char) c));
    }

    public int read(byte[] b, int offset, int len) throws IOException {
	int result = super.read(b, offset, len);
	for (int i = offset; i < offset + result; i++) {
	    b[i] = (byte) Character.toLowerCase((char) b[i]);
	}
	return result;
    }
}
package com.thecafetechno.structural.decoratorPattern;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class DecoratorClient {

    public static void main(String[] args) throws IOException {
	int c;
	try {
	    InputStream in = new InputStreamDecorator(new BufferedInputStream(
		    new FileInputStream("decorator.txt")));
	    while ((c = in.read()) >= 0) {
		System.out.print((char) c);
	    }
	    in.close();
	} catch (IOException e) {
	    e.printStackTrace();
	}
    }
}

Decorator Pattern Vs Adapter


Adapter and Decorator’s similarity?

  • They both wrap objects at run-time
  • They both delegate requests to their wrapped objects

Adapter and Decorator are different?

  • Adapter converts one interface into another while maintaining functionality (extends Target, compose Adaptee)
  • Decorator leaves the interface alone but adds new functionality (extends and compose Object to decorate)
  • Decorators are designed to be “stacked”; that’s less likely to occur with adapter

Template method pattern in Java with sample code

Template Method pattern is a behavioral design pattern. It is among one of the most widely used design patterns. It defines the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.

Sometimes you want to specify the order of operations (or steps) that a method uses, but allow subclasses to provide their own implementations of some of these operations.

Real World Examples of Template Pattern:

  • Servlet (explained after example)
  • Java – MergeSort , Arrays sort(Refer Head First Book)
  • JFrame – update() (Refer Head First Book)
  • HibernateCallback used in HibernateTemplate’s execute(..) methods
  • Struts – RequestProcessor

Case Study:
Develop an application for processing flat file for
1. Stock
2. Derivatives

Requirements:
Stock support CSV format, where as Derivative support txt. Stock data is separated by delimiter “,”, where as Derivative data within Flat file separated by “|”. Data is persisted within database. We can configure logging into system optionally.

Class Diagram:

Explanation:
DataHandler provide template method to algorithm for processing financial system data files.
Algorithm: Template Method – execute()
1. Validate file type
2. Transform Data
3. Process Data
Subclass should implement specific behaviour based on investment file type (Stock/Derivative).
Hook: Method – isDebugMode()
DataHandler define default configuration for setting log in debug mode. Subclass can override this method. Subclass can use hook to control execution of algorithm.

Code:
Template Class

package com.thecafetechno.behavioral.templateMethodPattern;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;

/**
 * DataHandler provide template method execute which define algorithm for
 * processing financial system data files.
 *
 * Algorithm: 1. Validate file type 2. Transform Data 3. Process Data
 *
 * Subclass should implement specific behaviour based on investment file type
 * (Stock/Derivative).
 *
 */

public abstract class DataHandler {
    /**
     * This is template method define algorithm for accessing financial system
     * data files.
     *
     * @param fileName
     *            String
     */

    public final void execute(String fileName) {
	if (isValidFileType(fileName)) {
	    try { // process file
		// Open the file that is the first
		FileInputStream fstream = new FileInputStream(fileName);

		// Get the object of DataInputStream
		DataInputStream in = new DataInputStream(fstream);
		BufferedReader br = new BufferedReader(
			new InputStreamReader(in));
		String strLine;

		// Read File Line By Line
		while ((strLine = br.readLine()) != null) {
		    if (isDebugMode()) {
			System.out.println("Processing data:" + strLine);
		    }
		    DataObject data = transformData(strLine);
		    process(data);
		}
		// Close the input stream
		in.close();
	    } catch (Exception e) { // Catch exception if any
		System.err.println("Error:" + e.getMessage());
	    }
	}
    }

    /**
     * Validate File type. Subclass should implement specific behaviour.
     *
     * @param fileName
     *            String
     * @return boolean
     */
    protected abstract boolean isValidFileType(String fileName);

    /**
     * Transform data to data Object. Subclass should implement specific
     * behaviour.
     *
     * @param fileName
     *            String
     * @return DataObject
     */
    protected abstract DataObject transformData(String fileName);

    /**
     * Subclass should override this method to persist/process data within
     * database.
     *
     * @param data
     *            DataObject
     */
    protected abstract void process(DataObject data);

    /**
     * This is a hook method and DataHandler define default configuration for
     * setting log in debug mode. Subclass can override this method. Subclass
     * can use hook to control execution of algorithm.
     *
     * @return boolean
     */

    protected boolean isDebugMode() {
	return false;
    }
}

Template SubClass StockHandler:


package com.thecafetechno.behavioral.templateMethodPattern;

import java.math.BigDecimal;
import java.util.StringTokenizer;

public class StockHandler extends DataHandler {
    @Override
    protected boolean isValidFileType(String fileName) {
	// Support processing of file if in CSV format
	return fileName.endsWith(".csv");
    }

    @Override
    protected void process(DataObject data) {
	if (isDebugMode()) {
	    log("Persisting Data!!!");
	}

	// Persist information
	StockDataObject dataVal = (StockDataObject) data;
	log("Stock Name:" + dataVal.getName());
	log("High Value:" + dataVal.getHighValue().toString());
	log("Low Value:" + dataVal.getLowValue().toString());
	log("Open Value:" + dataVal.getOpenValue().toString());
	log("Close Value:" + dataVal.getCloseValue().toString());
    }

    @Override
    protected DataObject transformData(String strLine) {
	if (isDebugMode()) {
	    log("\nStarted Transformation!!!");
	}
	StringTokenizer tokenizer = new StringTokenizer(strLine, ",");
	StockDataObject dataObject = null;
	if (tokenizer.hasMoreTokens() && tokenizer.countTokens() == 5) {
	    dataObject = new StockDataObject();
	    dataObject.setName(tokenizer.nextToken());
	    dataObject.setOpenValue(new BigDecimal(tokenizer.nextToken()));
	    dataObject.setHighValue(new BigDecimal(tokenizer.nextToken()));
	    dataObject.setLowValue(new BigDecimal(tokenizer.nextToken()));
	    dataObject.setCloseValue(new BigDecimal(tokenizer.nextToken()));
	}
	if (isDebugMode()) {
	    log("Transform Successful!!!");
	}
	return dataObject;
    }

    private void log(String str) {
	System.out.println(str);
    }

    @Override
    protected boolean isDebugMode() {
	return true;
    }
}

DerivativeHandler


package com.thecafetechno.behavioral.templateMethodPattern;

public class DerivativeHandler extends DataHandler {
    @Override
    protected boolean isValidFileType(String fileName) {
	// Support processing of file if in txt format
	return fileName.endsWith(".txt");
    }

    @Override
    protected void process(DataObject data) {
	System.out.println("Process data for derivative!!!");
    }

    @Override
    protected DataObject transformData(String fileName) {
	System.out.println("Transforming data for derivative!!!");
	return null;
    }
}

Reference DataObject Class


package com.thecafetechno.behavioral.templateMethodPattern;

import java.io.Serializable;

public interface DataObject extends Serializable {

}

Data Object for Stock.

package com.thecafetechno.behavioral.templateMethodPattern;

import java.math.BigDecimal;

/*
 * Data Object for Stock
 */
public class StockDataObject implements DataObject {

    private static final long serialVersionUID = 1L;
    private String name;
    private BigDecimal openValue;
    private BigDecimal highValue;
    private BigDecimal lowValue;
    private BigDecimal closeValue;

    public String getName() {
	return name;
    }

    public void setName(String name) {
	this.name = name;
    }

    public BigDecimal getOpenValue() {
	return openValue;
    }

    public void setOpenValue(BigDecimal openValue) {
	this.openValue = openValue;
    }

    public BigDecimal getHighValue() {
	return highValue;
    }

    public void setHighValue(BigDecimal highValue) {
	this.highValue = highValue;
    }

    public BigDecimal getCloseValue() {
	return closeValue;
    }

    public void setCloseValue(BigDecimal closeValue) {
	this.closeValue = closeValue;
    }

    public BigDecimal getLowValue() {
	return lowValue;
    }

    public void setLowValue(BigDecimal lowValue) {
	this.lowValue = lowValue;
    }
}

 

package com.thecafetechno.behavioral.templateMethodPattern;

import java.math.BigDecimal;

/*
 * Data Object for Stock
 */
public class StockDataObject implements DataObject {

    private static final long serialVersionUID = 1L;
    private String name;
    private BigDecimal openValue;
    private BigDecimal highValue;
    private BigDecimal lowValue;
    private BigDecimal closeValue;

    public String getName() {
	return name;
    }

    public void setName(String name) {
	this.name = name;
    }

    public BigDecimal getOpenValue() {
	return openValue;
    }

    public void setOpenValue(BigDecimal openValue) {
	this.openValue = openValue;
    }

    public BigDecimal getHighValue() {
	return highValue;
    }

    public void setHighValue(BigDecimal highValue) {
	this.highValue = highValue;
    }

    public BigDecimal getCloseValue() {
	return closeValue;
    }

    public void setCloseValue(BigDecimal closeValue) {
	this.closeValue = closeValue;
    }

    public BigDecimal getLowValue() {
	return lowValue;
    }

    public void setLowValue(BigDecimal lowValue) {
	this.lowValue = lowValue;
    }
}

Client Class:


package com.thecafetechno.behavioral.templateMethodPattern;

/*
 * Sample client to test Template Pattern.
 */
public class TemplateMethodClient {

    public static void main(String[] args) {
	DataHandler handler = new StockHandler();
	handler.execute("test.csv");
    }
}

Real World Example of Template Method Pattern: Servlet
Servlet Life Cycle
init()
service()
destroy()
Service method is an abstract method in GenericServlet Class.
HttpServlet extends GenericServlet and implement service method.
Based on HTTP request type, HTTPServlet invokes
- doGet, doPost, doHead, doPut, doDelete, doTrace, doOptions
Developers extend HttpServlet and write meaningful method – doGet, doPost
Template – HttpServlet service method define template for handling HTTP requests.

Intresting Fact about Template Method Pattern: Template Method follow
Hollywood Principle – “Don’t call me, I will call you”
Enforces “Open Closed principle” – A class should be open for extension, but closed for modification.