DESIGN PATTERNS
There are three design patterns described. They are as follows:
1)Structural
2)Creational
3)Behavioral
Structural Patterns
Structural Patterns describe how objects and classes can be combined to form larger structures.
There are seven structural patterns described. They are as follows:
1.Adapter
2.Bridge
3.Composite
4.Decorator
5.Facade
6.Flyweight
7.Proxy
Decorator pattern attaches additional responsibilities to an object dynamically. Provide a flexible alternative to subclassing for extending functionality.
It is used in various Java IO classes. java.io.BufferedReader; java.io.FileReader;java.io.Reader;It’s a structural design pattern.
Decorator pattern allows to add new functionality an existing object without altering its structure. This type of design pattern comes under structural pattern as this pattern acts as a wrapper to existing class. This pattern creates a decorator class which wraps the original class and provides additional functionality keeping class methods signature intact.
Advantage
Decorator Pattern is flexible than inheritance because inheritance add responsibilities at compile time and it will add at run-time.
Disadvantage
Code maintenance can be a problem as it provides a lot of similar kind of small objects (each decorator).
Implementation
The decorator pattern helps to add behavior or responsibilities to an object. This is also called “Wrapper”. Suppose we have some 6 objects and 2 of them need a special behavior, we can do this with the help of a decorator.
Java Design Patterns suggest that Decorators should be abstract classes and the concrete implementation should be derived from them. The decorator pattern can be use wherever there is a need to add some functionality to the object or group of objects. Let’s take an example of a Christmas tree. There is a need to decorate a Christmas tree. Now we have many branches which need to be decorated in different ways. Let’s have a look at the basic Decorator class.
Implementation
The decorator pattern helps to add behavior or responsibilities to an object. This is also called “Wrapper”. Suppose we have some 6 objects and 2 of them need a special behavior, we can do this with the help of a decorator.
**Decorator.java**
public abstract class Decorator {
public abstract void place(Branch branch);
}// End of class
This class has just one method place(). This method places different types of items on the branches of the tree.The class ChristmasTree is very simple and has just one method which returns a branch.
**ChristmasTree.java**
public class ChristmasTree {
private Branch branch;
public Branch getBranch() {
return branch;
}
}// End of class
Now we can decorate the branches in three different ways, one is by putting coloured balls on them, by putting coloured ruffles on them and also by putting stars on them.
Let’s have a look at the implementation of these three different types of decorators.
**BallDecorator.java** /*** Decorates the branch of the tree with* coloured balls.*/
public class BallDecorator extends Decorator {
// Default Constructor
public BallDecorator(ChristmasTree tree) {
Branch branch = tree.getBranch();
place(branch);
} /** The method places each decorative item* on the tree.*/
public void place(Branch branch) {
branch.put("ball");
}
}// End of class
Similarly, we can make StarDecorator and RufflesDecorator.
Now, we will see how to use the decorator. Its simple, we just are needed to pass the instance of ChristmasTree class to a decorator.StarDecorator decorator = new StarDecorator(new ChristmasTree());This way the decorator will be instantiated and a branch of the Christmas tree will be decorated.
Structural Patterns - Adapter Pattern
The Adapter pattern is used so that two unrelated interfaces can work together. The joining between them is called an Adapter. This is something like we convert interface of one class into interface expected by the client. We do that using an Adapter.
Let’s try and understand this with the help of an example.
Again, I will like to take a general example. We all have electric sockets in our houses of different sizes and shapes. I will take an example of a socket of 15 Ampere. This is a bigger socket and the other one which is smaller is of 5 Ampere. A 15 Amp plug cannot fit into a 5 Amp socket. Here, we will use an Adapter. The adapter can be called a connector here. The connector connects both of these and gives output to the client plug which is of 5Amp.The Adapter is something like this. It will be having the plug of suitable for 15 Amp and a socket suitable for a 5 Amp plug. So, that the 5 Amp plug which here is the client can fit in and also the server which here is the 15 Amp socket can give the output.
Let’s try and convert the same example into a software program. How do we do this? Let’s try and understand the problem once more. We have a 5 Amp plug and want a 5 Amp socket so that it can work. We DO NOT have a 5 Amp socket, what we have is a 15 Amp socket in which the 5 Amp plug cannot fit. The problem is how to cater to the client without changing the plug or socket.
The Adapter Pattern can be implemented in two ways, by Inheritance and by Composition. Here is the example of Adapter by Inheritance:
Let’s say there is a socket interface.
**Socket.java** /*** The socket class has a specs for 15 AMP.*/
public interface Socket {
/*** This method is used to match the input to be* given to the Plug
* @return Output of the Plug (Client)*/
public String getOutput();
}// End of interface
And there is a class Plug which wants the input of 5 AMP. This is the client.
**Plug.java** /*** The input for the plug is 5 AMP. which is a* mismatch for a 15 AMP socket.
** The Plug is the client. We need to cater to* the requirements of the Plug.*/
public class Plug {
private String specification = "5 AMP";
public String getInput() {
return specification;
}
}// End of class
Finally, there will be an adapter class. This will inherit the socket and give output for Plug.
**ConnectorAdapter.java** /*** ConnectorAdapter has is the connector between* the socket and plug so as to make the interface* of one system to suit the client.*/
public class ConnectorAdapter implements Socket {
/*** Method coming from the interface* Socket which we have to make to
* fit the client plug * @return Desired output of 5 AMP*/
public String getOutput() {
Plug plug = new Plug();
String output = plug.getInput();
return output;
}
}// End of class
This class implements the getOutput() method of Socket and sets it to fit the client output.Similarly, let’s consider the Association and Composition of objects by which Adapter can be implemented.The class Socket gives the 15 AMP output.
**Socket.java**/*** Class socket giving the 15 AMP output.*/
public class Socket {
/**
* Output of 15AMP returned.
*
* @return Value of output from socket
*/
public String getOutput() {
return "15 AMP";
}
}// End of class
There is an interface Plug.java which has a method getInput(). This is the client and we need to adapt the output for this input which is 5 AMP. Plug.java
/*** The input for the plug is 5 AMP. which is a
* mismatch for a 15 AMP socket.** The Plug is the client. We need to cater to* the requirements of the Plug.*/
public interface Plug {
public String getInput();
}// End of class
Plug5AMP is the implementation of Plug which requires 5 AMP of input.
Plug5AMP.java
public class Plug5AMP implements Plug {
/*** Get the input of client i.e. Plug* @return 5 AMP*/
public String getInput() {
return "5 AMP";
}
}// End of class
The Adapter here takes output from the Socket. If the output is what is needed, it gives it to the Plug else, it overrides the value and returns the adapter output.
ConnectorAdapter.java
/*** Using composition*/
public class ConnectorAdapter {
Plug5AMP plug5;
public ConnectorAdapter(Plug5AMP plug) {
this.plug5 = plug;
}
public static void main(String[] args) {
// Taking output from the Socket
Socket socket = new Socket();
String outputFromSocket = socket.getOutput();
// Giving away input to the Plug
ConnectorAdapter adapter = new ConnectorAdapter(new Plug5AMP());
String inputToPlug = adapter.getAdapterOutput(outputFromSocket);
System.out.println("New output by adapter is: "+inputToPlug);
}
public String getAdapterOutput(String outputFromScoket) {
/** if output is same, return*/
if (outputFromScoket.equals(plug5.getInput())) {
return outputFromScoket;
}
/** Else, override the value by adapterOutput*/
else {
String adapterOutput = plug5.getInput();
return adapterOutput;
}
}// End of class
Conclusion
This is how the Adapter pattern works. When one interface cannot be changed and has to be suited to the again cannot-be-changed client, an adapter is used so that both the interfaces can work together.
Structural Patterns - Bridge Pattern
The Bridge Pattern is used to separate out the interface from its implementation. Doing this gives the flexibility so that both can vary independently.
The best example for this is like the electric equipments you have at home and their switches. For e.g., the switch of the fan. The switch is the interface and the actual implementation is the Running of the fan once its switched-on. Still, both the switch and the fan are independent of each other. Another switch can be plugged in for the fan and this switch can be connected to light bulb.Let’s see how we can convert this into a software program. Switch is the interface having two functions, switchOn() and switchOff().
Here is the sample code for Switch.
Switch.java /*** Just two methods. on and off.*/
public interface Switch {
// Two positions of switch.
public void switchOn();
public void switchOff();
}// End of interface
This switch can be implemented by various devices in house, as Fan, Light Bulb etc. Here is the sample code for that.
Fan.java /** Implement the switch for Fan*/
public class Fan implements Switch {
// Two positions of switch.
public void switchOn() {
System.out.println("FAN Switched ON");
}
public void switchOff() {
System.out.println("FAN Switched OFF");
}
}// End of class
And implementation as Bulb.
Bulb.java /*** Implement the switch for Fan*/
public class Bulb implements Switch {
// Two positions of switch.
public void switchOn() {
System.out.println("BULB Switched ON");
}
public void switchOff() {
System.out.println("BULB Switched OFF");
}
}// End of class
Here, we can see, that the interface Switch can be implemented in different ways. Here, we can easily use Switch as an interface as it has only two functions, on and off. But, there may arise a case where some other function be added to it, like change() (change the switch). In this case, the interface will change and so, the implementations will also changed, for such cases, you should use the Switch as abstract class. This decision should be made earlier to implementation whether the interface should be interface or abstract class.
Structural Patterns - Composite Pattern
In developing applications, we come across components which are individual objects and also can be collection of objects. Composite pattern can represent both the conditions. In this pattern, you can develop tree structures for representing part-whole hierarchies.The most common example in this pattern is of a company’s employee hierarchy. We here will also take the same example.The employees of a company are at various positions. Now, say in a hierarchy, the manager has subordinates; also the Project Leader has subordinates, i.e. employees reporting to him/her. The developer has no subordinates.
So, let’s have a look at the class Employee: This is a simple class with getters and setters for attributes as name, salary and subordinates.
**Employee.java**
import java.util.Vector;
public class Employee {
private String name;
private double salary;
private Vector subordinates;
public Vector getSubordinates() {
return subordinates;
}
public void setSubordinates(Vector subordinates) {
this.subordinates = subordinates;
}
// constructor
public Employee(String name, double sal) {
setName(name);
setSalary(sal);
subordinates = new Vector();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public void add(Employee e) {
subordinates.addElement(e);
}
public void remove(Employee e) {
subordinates.remove(e);
}
}// End of interface
Next we, fill up the tree. You can make a class to access the class Employee and try filling up the tree like this:
/** This will add employess to the tree. The boss, is PM* and has subordinates.*/
private void addEmployeesToTree() {
CFO = new Employee("CFO", 30000);
Employee headFinance1 = new Employee("Head Finance. North Zone", 20000);
Employee headFinance2 = new Employee("Head Finance. West Zone", 22000);
Employee accountant1 = new Employee("Accountant1", 10000);
Employee accountant2 = new Employee("Accountant2", 9000);
Employee accountant3 = new Employee("Accountant3", 11000);
Employee accountant4 = new Employee("Accountant4", 12000);
CFO.add(headFinance1);
CFO.add(headFinance2);
headFinance1.add(accountant1);
headFinance1.add(accountant4);
headFinance2.add(accountant2);
headFinance2.add(accountant3);
}// End of class
Once we have filled the tree up, now we can get the tree for any employee and find out whether that employee has subordinates with the following condition. Vector subOrdinates = emp.getSubordinates(); if (subOrdinates.size() != 0) getTree(subOrdinates); else System.out.println("No Subordinates for the Employee: "+emp.getName());
Thus the Composite pattern allows you to create a tree like structure for simple and complex objects so they appear the same to the client.
Structural Patterns - 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.Let’s try and understand the facade pattern better using a simple example. Let’s consider a store. This store has a store keeper. In the storage, there are a lot of things stored e.g. packing material, raw material and finished goods.You, as client want access to different goods. You do not know where the different materials are stored. You just have access to store keeper who knows his store well. Whatever you want, you tell the store keeper and he takes it out of store and hands it over to you on showing him the credentials. Here, the store keeper acts as the facade, as he hides the complexities of the system Store. Let us see how the Store example works.
**Store.java**
public interface Store {
public Goods getGoods();
}// End of interface
The store can very well be an interface. This only returns Goods. The goods are of three types as discussed earlier in this document. RawMaterialGoods, FinishedGoods and PackagingMaterialsGoods. All these classes can implement the Goods interface.Similarly, the stores are of three types and can implement the Store interface. Let’s have a look at the code for one of the stores.
**FinishedGoodsStore.java**
public class FinishedGoodsStore implements Store {
public Goods getGoods() {
FinishedGoods finishedGoods = new FinishedGoods();
return finishedGoods;
}
}// End of class
Now let’s consider the facade StoreKeeper.
**StoreKeeper.java**
public class StoreKeeper {
/*** The raw materials are asked for and* are returned
** @return raw materials*/
public RawMaterialGoods getRawMaterialGoods() {
RawMaterialStore store = new RawMaterialStore();
RawMaterialGoods rawMaterialGoods = (RawMaterialGoods)store.getGoods();
return rawMaterialGoods;
}
/*** The packaging materials are asked for and* are returned** @return packaging materials*/
public PackingMaterialGoods getPackingMaterialGoods() {
PackingMaterialStore store = new PackingMaterialStore();
PackingMaterialGoods packingMaterialGoods = (PackingMaterialGoods)store.getGoods();
return packingMaterialGoods;
}
/*** The finished goods are asked for and* are returned
** @return finished goods*/
public FinishedGoods getFinishedGoods() {
FinishedGoodsStore store = new FinishedGoodsStore();
FinishedGoods finishedGoods = (FinishedGoods)store.getGoods();
return finishedGoods;
}
}// End of class
This is clear that the complex implementation will be done by StoreKeeper himself. The client will just access the StoreKeeper and ask for either finished goods, packaging material or raw material.How will the client program access this façade? Here is a simple code.
**Client.java**
public class Client {
/*** to get raw materials*/
public static void main(String[] args) {
StoreKeeper keeper = new StoreKeeper();
RawMaterialGoods rawMaterialGoods = keeper.getRawMaterialGoods();
}
}// End of class
In this way the implementation is left to the façade. The client is given just one interface and can access only that. This hides all the complexities.There is another way of implementing this. We can have just one method in our StoreKeeper class getGoods(String goodsType).
Another version of StoreKeeper method is here.
**StoreKeeper.java**
public class StoreKeeper {
/*** The common method** @return Goods*/
public Goods getGoods(String goodsType) {
if (goodsType.equals("Packaging")) {
PackingMaterialStore store = new PackingMaterialStore();
PackingMaterialGoods packingMaterialGoods = (PackingMaterialGoods)store.getGoods();
return packingMaterialGoods;
}
else if (goodsType.equals("Finished")) {
FinishedGoodsStore store = new FinishedGoodsStore();
FinishedGoods finishedGoods = (FinishedGoods)store.getGoods();
return finishedGoods;
}
else {
RawMaterialStore store = new RawMaterialStore();
RawMaterialGoods rawMaterialGoods = (RawMaterialGoods)store.getGoods();
return rawMaterialGoods;
}
}// End of class
The client program can now create an object of StoreKeeper class and call method getGoods() passing as parameter the type of goods required. This can be done as follows. new StoreKeeper().getGoods(“RawMaterials”);In this case, the type-casting ill be needed on client side to narrow down Goods to RawMaterialsGoods.All in all, the Façade pattern hides the complexities of system from the client and provides a simpler interface. Looking from other side, the facade also provides the implementation to be changed without affecting the client code.
Structural Patterns - Proxy Pattern
The proxy pattern 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
The cases can be innumerable why we can use the proxy. Let’s take a scenario. Say, we want to attach an image with the email. Now, suppose this email has to be sent to 1 lakh consumers in a campaign. Attaching the image and sending along with the email will be a very heavy operation. What we can do instead is, send the image as a link to one of the servlet. The place holder of the image will be sent. Once the email reaches the consumer, the image place holder will call the servlet and load the image at run time straight from the server.
Let’s try and understand this pattern with the help of a non-software example as we have tried to do throughout this article.Let’ say we need to withdraw money to make some purchase. The way we will do it is, go to an ATM and get the money, or purchase straight with a cheque. In old days when ATMs and cheques were not available, what used to be the way??? Well, get your passbook, go to bank, get withdrawal form there, stand in a queue and withdraw money. Then go to the shop where you want to make the purchase. In this way, we can say that ATM or cheque in modern times act as proxies to the Bank. Let’s look at the code now.Bank will define the entire method described above. There are references of classes like You (as the person who wants to withdraw money), also Account, as persons account. These are dummy classes and can be considered of fulfilling the responsibilities as described.
**Bank.java**
/*** Bank.java* The class acts as the main object for which * the proxy has to be created. As described, going* to bank for withdrawal is very costly time wise.*/
public class Bank {
private int numberInQueue;
/*** Method getMoneyForPurchase* This method is responsible for the entire banking* operation described in the write-up*/
public double getMoneyForPurchase(double amountNeeded) {
// get object for person
You you = new You("Prashant");
// get obj for account
Account account = new Account();
// get person's account number
String accountNumber = you.getAccountNumber();
// passbook got.
boolean gotPassbook = you.getPassbook();
// get number in queue
int number = getNumberInQueue();
// the number will decrease every few mins
while (number != 0) {
number--;
}
// now when the number = 0, check if balance is sufficient
boolean isBalanceSufficient = account.checkBalance(accountNumber, amountNeeded);
if(isBalanceSufficient)
return amountNeeded;
else
return 0;
}
/*** returns the number in the queue*/
private int getNumberInQueue() {
return numberInQueue;
}
}// End of class
Also, the second class is ATMProxy. This also defines the way the transaction can be handled for withdrawal of money.
**ATMProxy.java**
public class ATMProxy {
/*** Method getMoneyForPurchase* This method is responsible for the entire banking* operation described in the write-up*/
public double getMoneyForPurchase(double amountNeeded) {
// get obj of You to get card
You you = new You("Prashant");
// get obj for account
Account account = new Account();
boolean isBalanceAvailable = false;
// if card there, go ahead
if(you.getCard()) {
isBalanceAvailable = account.checkBalance(you.getAccountNumber(), amountNeeded);
}
if(isBalanceAvailable)
return amountNeeded;
else
return 0;
}
}// End of class
Here, we can also create another proxy called ChequeProxy. I am not creating it here as the message I wanted to send across has been conveyed with the help of one proxy only. We can see here that creation of object of Bank is very costly, effort and time wise, and so, we can as well use a proxy called ATM to get the result. ATM can internally communicate with the Bank object. So, ATM here is also acting like a façade. This might and might not happen. It can happen that we at a later stage have to create the same heavy object. We just want to postpone the creation of object to the last minute so that the application is not loaded by resources utilized for creating the object.
Structural Patterns - Flyweight Pattern
The pattern here 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.
Creational Patterns
All the creational patterns define the best possible way in which an object can be instantiated. These describes the best way to CREATE object instances.
There are five types of Creational Patterns.
Factory Pattern
Abstract Factory Pattern
Builder Pattern
Prototype Pattern
Singleton Pattern
Creational Patterns - Singleton Pattern
There are some instances in the application where we have to use just one instance of a particular class. A very simple example is say Logger, suppose we need to implement the logger and log it to some file according to date time. In this case, we cannot have more than one instances of Logger in the application otherwise the file in which we need to log will be created with every instance. We use Singleton pattern for this and instantiate the logger when the first request hits or when the server is started. Example: We suppress the constructor and don’t allow even a single instance for the class. But we declare an attribute for that same class inside and create instance for that and return it. You need to be careful with multiple threads. If you don’t synchronize the method which is going to return the instance then, there is a possibility of allowing multiple instances in a multi-threaded scenario. Do the synchronization at block level considering the performance issues.
public class Singleton {
private static Singleton singleInstance;
private Singleton() {}
public static Singleton getSingleInstance() {
if (singleInstance == null) {
synchronized (Singleton.class) {
if (singleInstance == null) {
singleInstance = new Singleton();
}
}
}
return singleInstance;
}
Creational Patterns - 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.
class Bike implements Cloneable {
private int gears;
private String bikeType;
private String model;
public Bike() {
bikeType = "Standard";
model = "Leopard";
gears = 4;
} public Bike clone() {
return new Bike();
}
public void makeAdvanced() {
bikeType = "Advanced";
model = "Jaguar";
gears = 6;
}
public String getModel(){
return model;
}
} public class Workshop {
public Bike makeJaguar(Bike basicBike) {
basicBike.makeAdvanced();
return basicBike;
}
public static void main(String args[]){
Bike bike = new Bike();
Bike basicBike = bike.clone();
Workshop workShop = new Workshop();
Bike advancedBike = workShop.makeJaguar(basicBike);
System.out.println("Prototype Design Pattern: "+advancedBike.getModel());
}
Creational Patterns - Factory Pattern
if we have a super class and n sub-classes, and based on data provided, we have to return the object of one of the sub-classes, we use a factory pattern.
Let’s take an example to understand this pattern.
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.
public class Person {
// name string
public String name;
// gender : M or F
private String gender;
public String getName() {
return name;
}
public String getGender() {
return gender;
}
}// End of class
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.
public class Male extends Person {
public Male(String fullName) {
System.out.println("Hello Mr. "+fullName);
}
}// End of class
Also, the class Female
public class Female extends Person {
public Female(String fullNname) {
System.out.println("Hello Ms. "+fullNname);
}
}// End of class
Now, we have to create a client, or a SalutationFactory which will return the welcome message depending on the data provided.
public class SalutationFactory {
public static void main(String args[]) {
SalutationFactory factory = new SalutationFactory();
factory.getPerson(args[0], args[1]);
}
public Person getPerson(String name, String gender) {
if (gender.equals("M"))
return new Male(name);
else if(gender.equals("F"))
return new Female(name);
else
return null;
}
}// End of class
This class accepts two arguments from the system at runtime and prints the names. Running the program: After compiling and running the code on my computer with the arguments Prashant and M: java Prashant M The result returned is: “Hello Mr. Prashant”.
When to use a Factory Pattern?
The Factory patterns can be used in following cases:
When a class does not know which class of objects it must create.
A class specifies its sub-classes to specify which objects to create.
In programmer’s language (very raw form), you can use factory pattern where you have to create an object of any one of sub-classes depending on the data provided.
Creational Patterns - Abstract Factory Pattern
This pattern is one level of abstraction higher than factory pattern. This means that the abstract factory returns the factory of classes. Like Factory pattern returned one of the several sub-classes, this returns such factory which later will return one of the sub-classes.
Let’s understand this pattern with the help of an example. Suppose we need to get the specification of various parts of a computer based on which work the computer will be used for. The different parts of computer are, say Monitor, RAM and Processor. The different types of computers are PC, Workstation and Server. So, here we have an abstract base class Computer.
public abstract class Computer {
/*** Abstract method, returns the Parts ideal for* Server* @return Parts*/
public abstract Parts getRAM();
/*** Abstract method, returns the Parts ideal for* Workstation* @return Parts*/
public abstract Parts getProcessor();
/*** Abstract method, returns the Parts ideal for* PC* @return Parts*/
public abstract Parts getMonitor();
}// End of class
This class, as you can see, has three methods all returning different parts of computer. They all return a method called Parts. The specification of Parts will be different for different types of computers. Let’s have a look at the class Parts.
public class Parts {
/** specification of Part of Computer, String*/
public String specification;
/*** Constructor sets the name of OS* @param specification of Part of Computer*/
public Parts(String specification) {
this.specification = specification;
}
/*** Returns the name of the part of Computer** @return specification of PartofComputer, String*/
public String getSpecification() {
return specification;
}
}// End of class
And now lets go to the sub-classes of Computer. They are PC, Workstation and Server.
public class PC extends Computer {
/*** Method over-ridden from Computer, returns the Parts ideal for* Server* @return Parts*/
public Parts getRAM() {
return new Parts("512 MB");
}
/*** Method over-ridden from Computer, returns the Parts ideal for* Workstation*@return Parts*/
public Parts getProcessor() {
return new Parts("Celeron");
}
/*** Method over-ridden from Computer, returns the Parts ideal for* PC* @return Parts*/
public Parts getMonitor() {
return new Parts("15 inches");
}
}// End of class
public class Workstation extends Computer {
/*** Method over-ridden from Computer, returns the Parts ideal for* Server* @returnParts*/
public Parts getRAM() {
return new Parts("1 GB");
}
/*** Method over-ridden from Computer, returns the Parts ideal for*Workstation*@return Parts*/
public Parts getProcessor() {
return new Parts("Intel P 3");
}
/** Method over-ridden from Computer, returns the Parts ideal for* PC* @return Parts*/
public Parts getMonitor() {
return new Parts("19 inches");
}
}// End of class
public class Server extends Computer{
/*** Method over-ridden from Computer, returns the Parts ideal for* Server* @returnParts*/
public Parts getRAM() {
return new Parts("4 GB");
}
/*** Method over-ridden from Computer, returns the Parts ideal for* Workstation*@return Parts*/
public Parts getProcessor() {
return new Parts("Intel P 4");
}
/*** Method over-ridden from Computer, returns the Parts ideal for* PC* @return Parts*/
public Parts getMonitor() {
return new Parts("17 inches");
}
}// End of class
Now let’s have a look at the Abstract factory which returns a factory “Computer”. We call the class ComputerType.
/*** This is the computer abstract factory which returns one
* of the three types of computers.*/
public class ComputerType {
private Computer comp;
public static void main(String[] args) {
ComputerType type = new ComputerType();
Computer computer = type.getComputer("Server");
System.out.println("Monitor: "+computer.getMonitor().getSpecification());
System.out.println("RAM: "+computer.getRAM().getSpecification());
System.out.println("Processor: "+computer.getProcessor().getSpecification());
}
/*** Returns a computer for a type* @param computerType String, PC / Workstation / Server* @return Computer*/
public Computer getComputer(String computerType) {
if (computerType.equals("PC"))
comp = new PC();
else if(computerType.equals("Workstation"))
comp = new Workstation();
else if(computerType.equals("Server"))
comp = new Server();
return comp;
}
}// End of class
Running this class gives the output as this:Monitor: 17 inches RAM: 4 GB Processor: Intel P 4.
When to use Abstract Factory Pattern?
One of the main advantages of Abstract Factory Pattern is that it isolates the concrete classes that are generated. The names of actual implementing classes are not needed to be known at the client side. Because of the isolation, you can change the implementation from one factory to another.
Creational Patterns - Builder Pattern
Builder builds complex objects from simple ones step-by-step. It separates the construction of complex objects from their representation.
Let’s take a non-software example for this. Say, we have to plan for a children meal at a fast food restaurant. What is it comprised of? Well, a burger, a cold drink, a medium fries and a toy. This is common to all the fast food restaurants and all the children meals. Here, what is important? Every time a children’s meal is ordered, the service boy will take a burger, a fries, a cold drink and a toy. Now suppose, there are 3 types of burgers available. Vegetable, Fish and Chicken, 2 types of cold drinks available. Cola and Orange and 2 types of toys available, a car and a doll.
So, the order might be a combination of one of these, but the process will be the same. One burger, one cold drink, one fries and one toy. All these items are placed in a paper bag and is given to the customer.Now let’s see how we can apply software to this above mentioned example.
The whole thing is called a children meal. Each of the four burger, cold drink, fries and toy are items in the meal. So, we can say, there is an interface Item having two methods, pack() and price(). Let’s take a closer look at the interface Item:
**Item.java**
public interface Item {
/*** pack is the method, as every item will be packed* in a different way.
* E.g.:- The burger will be packed as wrapped in a paper* The cold drink will be given in a glass* The medium fries will be packed in a card box and* The toy will be put in the bag straight.* The class Packing is an interface for different types of* for different Items.*/
public Packing pack();
/** price is the method as all the items* burger, cold drink, fries will have a price.* The toy will not have any direct price, it will be given free with the meal.* The total price of the meal will be the combined* price of the three items.* @return price, int in rupees./
public int price();
}// End of class
So, we must now have a class defined for each of the items, as burger, toy, cold drink and fries. All these will implement the Item interface.
Lets start with Burger:
Burger.java
/** The class remains abstract as price method will be implemented* according to type of burger.
* @see price()* /
public abstract class Burger implements Item {
/*** A burger is packed in a wrapper. Its wrapped* in the paper and is served. The class Wrapper is * sub-class of Packing interface.* @return new Wrapper for every burger served.*/
public Packing pack() {
return new Wrapper();
}
/*** This method remains abstract and cannot be* given an implementation as the real implementation* will lie with the type of burger.* E.g.:- Veg Burger will have a different price from* a fish burger.
* @return price, int./
public abstract int price();
}// End of class
The class Burger can be further extended to VegBurger, FishBurger, ChickenBurger etc. These classes will each implement the price() method and return a price for each type of burger. I, in this example have given the implementation for VegBurger class.
VegBurger.java
/** The implementation of price method.*/
public class VegBurger extends Burger {
/*** This is the method implementation from* the super class Burger.
* @return price of a veg burger in rupees./
public int price() {
return 39;
}
}// End of class
Let’s concentrate on other items now. I, here for explanation purpose will give another item Fries.
Fries.java
/** Implements the Item interface.*/
public class Fries implements Item {
/*** Packing in which fries are served.* @return new Packing for every fries.
* Envelop is a packing in which fries are given/
public Packing pack() {
return new Envelop();
}
/*** Price of the medium fries.* @return int , price of medium fries in rupees*/
public int price() {
return 25;
}
}// End of class
Now, let’s see the Builder class, MealBuilder. This class is the one which serves the Children’s meal.
MealBuilder.java
/** Main builder class which builds the entire meal* for the customers*/
public class MealBuilder {
public Packing additems() {
Item[] items = {new VegBurger(), new Fries(), new Cola(), new Doll()}
return new MealBox().addItems(items);
}
public int calculatePrice() {
int totalPrice = new VegBurger().price() + new Cola().price() + new Fries().price() + new Doll().price();
return totalPrice;
}
}// End of class
This class gives the total meal and also presents the total price. Here, we have abstracted the price calculation and meal package building activity from the presentation, which is a meal box. The Builder pattern hides the internal details of how the product is built. Each builder is independent of others. This improves modularity and makes the building of other builders easy. Because, each builder builds the final product step by step, we have more control on the final product.
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 behavioral patterns are:
Data Access Object Pattern
Command Pattern
Mediator Pattern
Strategy Pattern
Behavioral Patterns - Mediator Pattern
The mediator pattern deals with the complexity which comes in the coding when number of classes increase. I will explain this. When we begin with development, we have a few classes and these classes interact with each other producing results. Now, consider slowly, the logic becomes more complex and functionality increases. Then what happens? We add more classes and they still interact with each other but it gets really difficult to maintain this code now. Mediator pattern takes care of this problem. Mediator makes the code more maintainable. It promotes loose-coupling of classes such that only one class (Mediator) has the knowledge of all the classes, rest of the classes have their responsibilities and they only interact with the Mediator.
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. Another popular example is Stock exchange. In old days when there were no stock markets, the individual brokers used to buy or sell commodities among themselves. They used to face huge risks, of defaulting of counterparty, limited information (as, only limited deals in limited areas were possible), limited geographical reach, price variance (everyone could quote whatever price they wanted) and many more. So, the concept of stock exchange came into play.
For ex: BSE or NSE in India and NYSE, NASDAQ etc in the US. The stock exchange started acting like a mediator and the traders did not need to know other traders and services provided by them to make a deal. The traders have their own responsibilities as buyers and sellers and it was stock exchange’s responsibility to match their deals and get the settlement done. Many of the above mentioned risks were mitigated by this. But, there were some standardization procedures which came into picture because of this. All the traders who wanted to deal on stock exchange had to follow these standardization procedures. Let’s look at the code part:
/**
* StockExchange – this is the mediator class
*/
public class StockExchange {
public static void doTransaction (String typeOfTransaction, int quantity, Scrip scrip, Trader trader) {
Transaction transaction = new Transaction(typeOfTransaction, quantity, scrip, trader);
// try and match the current transaction
// with the ones saved in DB and find out
// whether a counter transaction is there or
// are there many such transactions which could
// fulfill requirement of this transaction.
matchTransaction(transaction)
}
public static getPrice (Scrip scrip) {
// try and match this transaction with all
// the saved ones. If they match till whatever extent
// trade for that. Then save, with status Traded for
// number of shares traded and save the rest as New.
}
}// End of class
/**
* Trader1 – this trader wants to sell 100 shares of company XYZ
*/
public class Trader1 {
public void doTransaction (String typeOfTransaction, int quantity) {
int expectedPrice = 320;
Scrip scrip = new Scrip(“XYZ”);
int price = StockExchange.getPrice(scrip);
if(typeOfTransaction.equals(“SELL”)){
if(price >= expectedPrice){
StockExchange.doTransaction(“SELL”, 100, scrip, trader1);
}
}else if(typeOfTransaction.equals(“BUY”)){
if(price <= expectedPrice){
StockExchange.doTransaction(“BUY”, 100, scrip, trader1);
}
}
}
}// End of class
/**
* Trader2 – this trader wants to buyl 100 shares of company XYZ
*/
public class Trader2 {
public void doTransaction (String typeOfTransaction, int quantity) {
int expectedPrice = 320;
Scrip scrip = new Scrip(“XYZ”);
int price = StockExchange.getPrice(scrip);
if(typeOfTransaction.equals(“SELL”)){
if(price >= expectedPrice){
StockExchange.doTransaction(“SELL”, 100, scrip, trader2);
}
}else if(typeOfTransaction.equals(“BUY”)){
if(price <= expectedPrice){
StockExchange.doTransaction(“BUY”, 100, scrip, trader2);
}
}
}
}// End of class
This is simple illustration of how we can use a mediator. Here are the main features of a mediator: • Responsibilities to individual objects. • Mediator is the only smart delegating object. • Transparency for other objects. • If more objects join in, only place of registration is Mediator, other objects do not need to know anything about the new object. • The code becomes very maintainable. On hind side, this brings standardization, which might be cumbersome. Also, there might be a slight loss in efficiency.
Behavioral Patterns - Strategy Pattern
In Strategy pattern, a class behavior or its algorithm can be changed at run time. This type of design pattern comes under behavior pattern. In Strategy pattern, we create objects which represent various strategies and a context object whose behavior varies as per its strategy object. The strategy object changes the executing algorithm of the context object.
Step 1
Strategy.java
public interface Strategy {
public int doOperation(int num1, int num2);
}
Step 2
Create concrete classes implementing the same interface.
OperationAdd.java
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
OperationSubstract.java
public class OperationSubstract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
OperationMultiply.java
public class OperationMultiply implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
Step 3
Create Context Class.
Context.java
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
Step 4
Use the Context to see change in behaviour when it changes its Strategy.
StatePatternDemo.java
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubstract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
}
Behavioral Patterns - Command Pattern
Command pattern is a data driven design pattern. A request is wrapped under a object as command and passed to invoker object. Invoker object looks for the appropriate object which can handle this command and pass the command to the corresponding object and that object executes the command. Implementation
We've created an interface Order which is acting as a command. We've created a Stock class which acts as a request. We've concrete command classes BuyStock and SellStock implementing Order interface which will do actual command processing. A class Broker is created which acts as a invoker object. It can take order and place orders.Broker object uses command pattern to identify which object will execute which command based on type of command. CommandPatternDemo, our demo class will use Broker class to demonstrate command pattern.
Step 1
Create a command interface.
Order.java
public interface Order {
void execute();
}
Step 2
Create a request class.
Stock.java
public class Stock {
private String name = "ABC";
private int quantity = 10;
public void buy(){
System.out.println("Stock [ Name: "+name+",
Quantity: " + quantity +" ] bought");
}
public void sell(){
System.out.println("Stock [ Name: "+name+",
Quantity: " + quantity +" ] sold");
}
}Step 3
Create concrete classes implementing the Order interface.
BuyStock.java
public class BuyStock implements Order {
private Stock abcStock;
public BuyStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.buy();
}
}SellStock.java
public class SellStock implements Order {
private Stock abcStock;
public SellStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.sell();
}
}Step 4
Create command invoker class.
Broker.java
import java.util.ArrayList;
import java.util.List;
public class Broker {
private List<Order> orderList = new ArrayList<Order>();
public void takeOrder(Order order){
orderList.add(order);
}
public void placeOrders(){
for (Order order : orderList) {
order.execute();
}
orderList.clear();
}}
Step 5
Use the Broker class to take and execute commands.
CommandPatternDemo.java
public class CommandPatternDemo {
public static void main(String[] args) {
Stock abcStock = new Stock();
BuyStock buyStockOrder = new BuyStock(abcStock);
SellStock sellStockOrder = new SellStock(abcStock);
Broker broker = new Broker();
broker.takeOrder(buyStockOrder);
broker.takeOrder(sellStockOrder);
broker.placeOrders();
}
}Step 6
Verify the output.
Stock [ Name: ABC, Quantity: 10 ] bought
Stock [ Name: ABC, Quantity: 10 ] sold
Behavioral Patterns – Data Access Object Pattern
Data Access Object Pattern or DAO pattern is used to separate low level data accessing API or operations from high level business services. Following are the participants in Data Access Object Pattern. Data Access Object Interface - This interface defines the standard operations to be performed on a model object(s).
Data Access Object concrete class -This class implements above interface. This class is responsible to get data from a datasource which can be database / xml or any other storage mechanism. Model Object or Value Object - This object is simple POJO containing get/set methods to store data retrieved using DAO class.
Implementation
Step 1
Create Value Object.
Student.java
public class Student {
private String name;
private int rollNo;
Student(String name, int rollNo){
this.name = name;
this.rollNo = rollNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getRollNo() {
return rollNo;
}
public void setRollNo(int rollNo) {
this.rollNo = rollNo;
}
}Step 2
Create Data Access Object Interface.
StudentDao.java
import java.util.List;
public interface StudentDao {
public List<Student> getAllStudents();
public Student getStudent(int rollNo);
public void updateStudent(Student student);
public void deleteStudent(Student student);
}
Step 3
Create concreate class implementing above interface.
StudentDaoImpl.java
import java.util.ArrayList;
import java.util.List;
public class StudentDaoImpl implements StudentDao {
//list is working as a database
List<Student> students;
public StudentDaoImpl(){
students = new ArrayList<Student>();
Student student1 = new Student("Robert",0);
Student student2 = new Student("John",1);
students.add(student1);
students.add(student2);
}
@Override
public void deleteStudent(Student student) {
students.remove(student.getRollNo());
System.out.println("Student: Roll No " + student.getRollNo()
+", deleted from database");
}
//retrive list of students from the database
@Override
public List<Student> getAllStudents() {
return students;
}
@Override
public Student getStudent(int rollNo) {
return students.get(rollNo);
}
@Override
public void updateStudent(Student student) {
students.get(student.getRollNo()).setName(student.getName());
System.out.println("Student: Roll No " + student.getRollNo()
+", updated in the database");
}
}Step 4
Use the StudentDao to demonstrate Data Access Object pattern usage.
CompositeEntityPatternDemo.java
public class DaoPatternDemo {
public static void main(String[] args) {
StudentDao studentDao = new StudentDaoImpl();
//print all students
for (Student student : studentDao.getAllStudents()) {
System.out.println("Student: [RollNo : "
+student.getRollNo()+", Name : "+student.getName()+" ]");
}
//update student
Student student =studentDao.getAllStudents().get(0);
student.setName("Michael");
studentDao.updateStudent(student);
//get the student
studentDao.getStudent(0);
System.out.println("Student: [RollNo : "
+student.getRollNo()+", Name : "+student.getName()+" ]");
}
}Step 5
Verify the output.
Student: [RollNo : 0, Name : Robert ]
Student: [RollNo : 1, Name : John ]
Student: Roll No 0, updated in the database
Student: [RollNo : 0, Name : Michael ]
Summary
The article illustrated the use of design patterns (structural, creational and behavioral) with examples and sample code which is both compelling and easy to grasp.