Thursday, February 26, 2015

Abstract Factory Design Pattern

Design Pattern > Creational Design Pattern > Abstract Factory Design Pattern

Abstract factory pattern provide the interface which used to create related or dependent objects without specifying their concrete classes.
The client remains completely unaware (decoupled) on which concrete products it gets from each of these individual factories and the client is only able to access a simplified interface.

Abstract factory pattern is also called factory of factories because return type of factory class methods are a abstract class( factory) which further creates the concrete object.

Key terms in Abstract Factory Design pattern :

AbstractFactory - declares a interface for operations that create abstract products.
ConcreteFactory - implements operations to create concrete products.
AbstractProduct - declares an interface for a type of product objects.
ConcreteProduct - defines a product to be created by the corresponding ConcreteFactory; it implements the AbstractProduct interface.
Client - uses the interfaces declared by the AbstractFactory and AbstractProduct classes.


Let's see a example. Suppose a computer manufacturer company has two factories one is LaptopFactory which manufactures hi-end and low-end laptops models HI_LAP_A, LOW_LAP_Z) and another factory is DesktopFactory which manufactures hi-end and low-end desktops models HI_DESK_A, LOW_DESK_Z .Based on client input either laptop or desktop, system prints the details of PCs i.e. final products.

We will create interface/abstract classes LowEndProductFactory and HiEndProductFactory as AbstractProduct and provide makeProduct() method to be implemented by actual products(laptop and Desktop models classes).

public interface LowEndProductFactory{

void makeProduct();
}

public interface HiEndProductFactory{

void makeProduct();
}

then AbstractComputerFactory would be our AbstractFactory interface which declares methods of return type as LowEndProductFactory and HiEndProductFactory.

public interface AbstractComputerFactory{

LowEndProductFactory creteLowEndPC();
HiEndProductFactory createHiEndPC();
}
this interface will be implemented by ConcreteFactory classes which are LaptopFactory and DesktopFactory.
finally our client class will print these product details based on the the user input as "laptop" or "desktop".

Java Implementation :

/**
 * AbstractProduct
 */
package com.kmingle.abstractfactory;

public interface HiEndProductFactory {

void getProductDetails();
}


/**
 * ConcreteProduct
 */
package com.kmingle.abstractfactory;

public class HI_LAP_A implements HiEndProductFactory {

/* (non-Javadoc)
* @see com.kmingle.abstractfactory.HiEndProductFactory#makeProduct()
*/
@Override
public void getProductDetails() {

System.out.println("Hi-end Laptop");

}

}


/**
 * ConcreteProduct
 */
package com.kmingle.abstractfactory;

public class HI_DESK_A implements HiEndProductFactory {

/* (non-Javadoc)
* @see com.kmingle.abstractfactory.HiEndProductFactory#makeProduct()
*/
@Override
public void getProductDetails() {

System.out.println("Hi-end Desktop");
}

}


/**
 * AbstractProduct
 */
package com.kmingle.abstractfactory;

public interface LowEndProductFactory {

void getProductDetails();
}


/**
 * ConcreteProduct
 */
package com.kmingle.abstractfactory;

public class LOW_LAP_Z implements LowEndProductFactory {

/* (non-Javadoc)
* @see com.kmingle.abstractfactory.LowEndProductFactory#makeProduct()
*/
@Override
public void getProductDetails() {

System.out.println("Low-end Laptop");
}

}


/**
 * ConcreteProduct
 */
package com.kmingle.abstractfactory;

public class LOW_DESK_Z implements LowEndProductFactory {

/* (non-Javadoc)
* @see com.kmingle.abstractfactory.LowEndProductFactory#makeProduct()
*/
@Override
public void getProductDetails() {

System.out.println("Low-end Desktop");
}

}


/**
 * AbstractFactory
 */
package com.kmingle.abstractfactory;

public interface AbstractComputerFactory {

LowEndProductFactory creteLowEndPC();
HiEndProductFactory createHiEndPC();
}


/**
 * ConcreteFactory
 */
package com.kmingle.abstractfactory;

public class LaptopFactory implements AbstractComputerFactory {

/* (non-Javadoc)
* @see com.kmingle.abstractfactory.AbstractComputerFactory#creteLowEndPC()
*/
@Override
public LowEndProductFactory creteLowEndPC() {
return new LOW_LAP_Z();
}

/* (non-Javadoc)
* @see com.kmingle.abstractfactory.AbstractComputerFactory#createHiEndPC()
*/
@Override
public HiEndProductFactory createHiEndPC() {
return new HI_LAP_A();
}

}


/**
 * ConcreteFactory
 */
package com.kmingle.abstractfactory;

public class DesktopFactory implements AbstractComputerFactory {

/* (non-Javadoc)
* @see com.kmingle.abstractfactory.AbstractComputerFactory#creteLowEndPC()
*/
@Override
public LowEndProductFactory creteLowEndPC() {
return new LOW_DESK_Z();
}

/* (non-Javadoc)
* @see com.kmingle.abstractfactory.AbstractComputerFactory#createHiEndPC()
*/
@Override
public HiEndProductFactory createHiEndPC() {
return new HI_DESK_A();
}

}


/**
 * Client Class
 */
package com.kmingle.abstractfactory;

import java.io.InputStream;
import java.util.Scanner;

public class AbstractFactoryClient {

public static void main(String[] args) {

AbstractComputerFactory acf;
while (true) {
System.out.println("enter your choice: ");
Scanner user_input = new Scanner( System.in );
String userChoice = user_input.next();
if ("laptop".equals(userChoice)) {
acf = new LaptopFactory();
printAvailableProducts(acf);
} else if ("desktop".equals(userChoice)) {
acf = new DesktopFactory();
printAvailableProducts(acf);
} else {
System.out.println("no product available");
System.exit(0);
}
}

}

private static void printAvailableProducts(AbstractComputerFactory acf) {

System.out.println("available products in entered choice are : ");
acf.createHiEndPC().getProductDetails();
acf.creteLowEndPC().getProductDetails();
}

}

OutPut :

enter your choice:
desktop
available products in entered choice are :
Hi-end Desktop
Low-end Desktop
enter your choice:
laptop
available products in entered choice are :
Hi-end Laptop
Low-end Laptop
enter your choice:
server
no product available


So, now if you want to add new product say server you need to create 1. server product classes by implementing productfactory interface 2. create serverfactory class by impplementing AbstractComputerFactory 3. add a condition for server in client class

Friday, February 20, 2015

Factory Method Design Pattern

Design Pattern > Creational Design Pattern > Factory Method Design Pattern

Factory Method Pattern isolates object creation logic with the client class. It defines an interface for creating an object, but leaves the choice of its type to the subclasses, creation being deferred at run-time.

Assume you have a ComputerFactory and based on product type objects are getting created. you can design your client class using if elase scenario

public class ComputerProductFactory {

String productType = System.in(); // input product type at runtime

if(productType.equals("Game"){

GamingPC hd= new GamingPC();
hd.someHDLogic();
}

if(productType.equals("MultiMedia"){

MultimediaPC kb= new MultimediaPC();
kb.someKBLogic();
}
}

public class GamingPC {

        String productType = null;

GamingPC(String pType){
this.productType = pType;
}

void someLogic(){
// method logic
}
}

public class MultimediaPC {

String productType = null;

MultimediaPC(String pType){
this.productType = pType;
}

void someLogic(){
// method logic
}
}

The problem in this approach is that a new product addition requires change in the client class also if any product is removed ( i.e. OldPC got outdated and will never be added to ComputerProductFactory) then some code ( else condition code ) would be obsolete.Assume in a big project if changes happens often then it's a nightmare to maintain the code.

Factory method pattern help in this scenario

Solution :
          In factory method pattern we abstract the object creation logic from client class and put that logic into a separate abstract class called Creator. Creator has the factory method which create and return product objects based on product type. This product type is passed as a parameter to factory method.Also, we define a new interface( Product ) for all product types.

the key terms in this pattern are -

Product -

  • An interface that serves as product type .


Concrete Product -

  • Class that Implements Product
  • Can have it's own behaviours ( methods )


Creator - 

  • Abstract class with factory method 
  • Factory Method can return default product


Concrete Creator -

  • Sub Class of Creator
  • Overrides factory method to create object of Concrete Product based on their type


Client -

  • Instantiate Concrete Creator
  • Calls factory method on Concrete Creator object to get Product 



Java Implementation :

/**
 * Product Interface
 */
package com.kmingle.factorymethod;

public interface ComputerProduct {

String getProductType();
void createProduct();
}


/**
 * Concrete Product
 */
package com.kmingle.factorymethod;

public class GamingPC implements ComputerProduct {

private String productType;

public GamingPC(String pType){
this.productType = pType;
}


public String getProductType() {
return productType;
}


/* (non-Javadoc)
* @see com.kmingle.factorymethod.ComputerProduct#createProduct()
*/
@Override
public void createProduct() {

System.out.println("creating GamingPC");
}

}


/**
 * Concrete Product
 */
package com.kmingle.factorymethod;

public class MultimediaPC implements ComputerProduct {

private String productType;

public MultimediaPC(String pType){
this.productType = pType;
}

public String getProductType() {
return productType;
}

/* (non-Javadoc)
* @see com.kmingle.factorymethod.ComputerProduct#createProduct()
*/
@Override
public void createProduct() {

System.out.println("creating MultimediaPC");
}

}


/**
 * Concrete Product
 */
package com.kmingle.factorymethod;

public class NormalPC implements ComputerProduct {

private String productType;

public NormalPC(String pType){
this.productType = pType;
}

public String getProductType() {
return productType;
}

/* (non-Javadoc)
* @see com.kmingle.factorymethod.ComputerProduct#createProduct()
*/
@Override
public void createProduct() {

System.out.println("creating NormalPC");
}

}


/**
 * creator abstract class
 */
package com.kmingle.factorymethod;

public abstract class DefaultCreator {

public ComputerProduct createFactoryProduct(String prodType){
return new NormalPC("Normal");
}
}


/**
 * Concrete Creator
 */
package com.kmingle.factorymethod;

public class ConcreteCreator extends DefaultCreator {

public ComputerProduct createFactoryProduct(String prodType){

if("Game".equals(prodType)){
return new GamingPC("Game");
}
else if("MultiMedia".equals(prodType)){
return new MultimediaPC("MultiMedia");
}
else{
return super.createFactoryProduct("Normal");
}
}
}


/**
 * Client Class
 */
package com.kmingle.factorymethod;

public class PCFactoryClient {

public static void main(String[] args) {

// instantiate concreate creator
ConcreteCreator cc = new ConcreteCreator();

// call factory method that returns object of type ComputerProduct
ComputerProduct cp = cc.createFactoryProduct("Normal");


// calls method on actual product
System.out.println("product type is :"+cp.getProductType());
cp.createProduct();

cp = cc.createFactoryProduct("Game");
System.out.println("product type is :"+cp.getProductType());
cp.createProduct();

cp = cc.createFactoryProduct("MultiMedia");
System.out.println("product type is :"+cp.getProductType());
cp.createProduct();
}

}

OutPut :

product type is :Normal
creating NormalPC
product type is :Game
creating GamingPC
product type is :MultiMedia
creating MultimediaPC


Another benefit is that you can use product classes in other applications as well because of loose coupling with client code.

Friday, February 13, 2015

Creational Design Pattern

Design Pattern > Creational Design Pattern

Creational design patterns abstract the object instantiation process.This pattern is used when the system has more and more object composition than inheritance. Also, composing systems with inheritance makes those systems too rigid. The creational patterns are designed to break this close coupling.

The consequences of creational patterns are :

1. You hide creational logic from the consument of an object-instance. As a consument you are not interested in how an instance is created. You only have a concrete demand (Service, Repository, etc.). Each demand is a dependency of your object.

2. You are able to insert dependencies from the outside, aka dependency injection. If you are able to inject/substitute dependencies of an object, you are better able to write unit-tests. Say you need the result of a complex DB-query or the result of several web-service-calls; you could easily inject those results from the outside or stub results. Furthermore you could mock / stub out the creational objects itself, which could be used to deliver other mocks / stubs.

Mainly used creational pattrns are :




4. Prototype

5. Singleton

Wednesday, February 11, 2015

Visitor Design Pattern

Design Pattern > Behavioral Design Pattern > Visitor Design Pattern

As per GOF the intention of visitor pattern is to "Represents an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates"


Let's understand it with an example. Suppose, you have created a basic banking application and your account structure is following :

Interface Account {

    int withdraw(int amount);
    int deposit(int amount);
}

class CheckingAccount Implements Account {
    String AccountType;
    int AccountBalance;

// getter setter

int withdraw(int amount){
// business logic
}

int deposit(int amount){
// business logic
}
}

class SavingsAccount Implements Account {
    String AccountType;
    int AccountBalance;

// getter setter

int withdraw(int amount){
// business logic
}

int deposit(int amount){
// business logic
}
}

So, client can perform deposit and withdrawal to their account, assume a new requirement arrive from the bank that offers all account holders to invest their say 10 percent money from savings account in a new Investment Account and bank needs to calculate total invested amount from across all the account.
One way you can modify the Account interface with doInvest operation and change all it's type classes structure. like below :

Interface Account {

    int withdraw(int amount);
    int deposite(int amount);

    int doInvest(int amount);
}

class CheckingAccount Implements Account {

// existing code

int doInvest(int amount){

// business logic
}

}

class SavingsAccount Implements Account {

// existing code

int doInvest(int amount){

// business logic
}

}

The problem in this approach is that in the feauture if new requirement come then you have to again change all the class structure.
Visitor pattern helps in these kind of situation.

Solution :
In visitor Pattern we design Element Interface( in our example Account interface) in suach a way so that it shouold not be changed with new requirements.Then the main interface Visitor whose objective is to perform action on Element classes.Visitor is desigend as per new requirement.

the key terms in this pattern are -
Element -

  • An Interface ( Account) with accept method whose parameter is a Visitor 

Concrete Element -

  • Implements Element interface
  • Calls visit method of Visitor object

Visitor -

  • An interface with visit method whose patameter is an Element

Concrete Visitor -

  • Implements Visitor interface
  • Actual operation (doInvest ) happens in visit method

ClientClass -

  • Create Element objects
  • Create Visitor object
  •        call accept method of elements as per requirement



Java Implementation :

/**
 *  Element interface
 */
package com.kmingle.visitor;

public interface Account {

double accept(AccountVisitor visitor);
}


/**
 * Concrete Element class
 */
package com.kmingle.visitor;

public class CheckingAccount implements Account {

private String accountType;
private int AccountBalance;

public CheckingAccount(String acType, int acBal){
this.accountType = acType;
this.AccountBalance = acBal;
}

public String getAccountType() {
return accountType;
}


public void setAccountType(String accountType) {
this.accountType = accountType;
}


public int getAccountBalance() {
return AccountBalance;
}


public void setAccountBalance(int accountBalance) {
AccountBalance = accountBalance;
}


/* (non-Javadoc)
* @see com.kmingle.visitor.Account#accept(com.kmingle.visitor.AccountVisitor)
*/
@Override
public double accept(AccountVisitor visitor) {

return visitor.visit(this);
}

}


/**
 * Concrete Element class
 */
package com.kmingle.visitor;

public class SavingsAccount implements Account {

private String accountType;
private int AccountBalance;

public SavingsAccount(String acType, int acBal){
this.accountType = acType;
this.AccountBalance = acBal;
}

public String getAccountType() {
return accountType;
}


public void setAccountType(String accountType) {
this.accountType = accountType;
}


public int getAccountBalance() {
return AccountBalance;
}


public void setAccountBalance(int accountBalance) {
AccountBalance = accountBalance;
}


/* (non-Javadoc)
* @see com.kmingle.visitor.Account#accept(com.kmingle.visitor.AccountVisitor)
*/
@Override
public double accept(AccountVisitor visitor) {

return visitor.visit(this);
}

}


/**
 *  Visitor interface
 */
package com.kmingle.visitor;

public interface AccountVisitor {

double visit(Account acount);

}


/**
 * Concrete Visitor Class
 */
package com.kmingle.visitor;

public class InvestmentAccountVisitor implements AccountVisitor {

/* (non-Javadoc)
* @see com.kmingle.visitor.AccountVisitor#visit(com.kmingle.visitor.Account)
*/
@Override
public double visit(Account account) {

double investedAmount = 0;

String className = account.getClass().getSimpleName();

if(className.equals("SavingsAccount")){
System.out.println("Account Type is SavingsAccount");
investedAmount = ((SavingsAccount)account).getAccountBalance()*0.1;
System.out.println("savings account balance = "+ ((SavingsAccount)account).getAccountBalance());
System.out.println("invested amount = "+ investedAmount);
return investedAmount;
}
else if(className.equals("CheckingAccount")){
System.out.println("Account Type is CheckingAccount");
System.out.println("can't invest from checking account");
}
else{
System.out.println("invalid account");
}
return 0;

}

}


/**
 * Visitor Client
 */
package com.kmingle.visitor;

import java.beans.Visibility;
import java.util.ArrayList;

public class InvestmentVisitorClient {

public static void main(String[] args) {

ArrayList accountList = new ArrayList();

accountList.add(new CheckingAccount("checking", 100));

accountList.add(new SavingsAccount("savings", 200));

accountList.add(new SavingsAccount("savings", 500));

double totalInvesteAmount = calculateInvestedAmount(accountList);

System.out.println("Total Invested Amount = "+ totalInvesteAmount);
}

private static double calculateInvestedAmount(ArrayList accountList) {

AccountVisitor visitor = new InvestmentAccountVisitor();

double investedAmount = 0;

for(Account account : accountList){

investedAmount = investedAmount + account.accept(visitor);
}

return investedAmount;
}

}


Output :

Account Type is CheckingAccount
can't invest from checking account
Account Type is SavingsAccount
savings account balance = 200
invested amount = 20.0
Account Type is SavingsAccount
savings account balance = 500
invested amount = 50.0
Total Invested Amount = 70.0


Further, you can create as many visitors as per your requirement without changing the structure of Element interface/classes.

Tuesday, February 3, 2015

Template Method Design Pattern

Design Pattern > Behavioral Design Pattern > Template Method Design Pattern

In some scenarios we want to write classes that follow certain algorithm structure but at the same allow different classes to define their own implementation of steps of algorithm. Template method pattern is helpful in these scenarios.

As per GOF the intent of template method pattern is to "Define 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."

It's not necessory to define all the steps of an algorithm. it depends of your requirements whether you wnat to use default step/operation of given algorithm from super class or want to define some or all operations/steps in your sub class.

There is a template method in super class which declare the order of algorithm operations/steps and sub classes need to define/override these operations( either some or all).At runtime template method calls the sub class operations in an order.

Key Terms :
Abstract Class - 

  • Class with template method
  • Subclasses can not override it's template method
  • Subclasses need to override it's operations declared in template method


Note - Super class need not to be abstract. in that case we need to call a hooks.The hooks are generally empty methods that are called in superclass (and does nothing because are empty), but can be implemented in subclasses.

Concrete Class - 

  •        Sub class that override operations declared in template method

Client Class - 

  • Create subclass instance that refers to superclass
  • calls template method of superclass to execute the algorithm


Java Implementation :

In this example an algorithm is defined to book a ticket in super class BookTicket and there are two subclasse BookTicketOnline and BookTicketIvr ( on phone call )


/**
 * An abstract class with template method
 */
package com.kmingle.template;

public abstract class BookMovieTicket {

public abstract void login();

public abstract void selectSource();

public abstract void selectDestination();

public void enterDetails(){
System.out.println("personal details entered from system");
}

public abstract void makePayment();

public final void bookTicket(){
login();
selectSource();
selectDestination();
enterDetails();
makePayment();
}
}


/**
 * Concrete Class
 */
package com.kmingle.template;

public class BookTicketOnline extends BookMovieTicket {

/* (non-Javadoc)
* @see com.kmingle.template.BookMovieTicket#login()
*/
@Override
public void login() {

System.out.println("online logged in");

}

/* (non-Javadoc)
* @see com.kmingle.template.BookMovieTicket#selectSource()
*/
@Override
public void selectSource() {

System.out.println("online Source selected");

}

/* (non-Javadoc)
* @see com.kmingle.template.BookMovieTicket#selectDestination()
*/
@Override
public void selectDestination() {

System.out.println("online Destination selected");

}

/* (non-Javadoc)
* @see com.kmingle.template.BookMovieTicket#makePayment()
*/
@Override
public void makePayment() {

System.out.println("online payment done");

}

}


/**
 * Concrete Class
 */
package com.kmingle.template;

public class BookTicketIvr extends BookMovieTicket {

/* (non-Javadoc)
* @see com.kmingle.template.BookMovieTicket#login()
*/
@Override
public void login() {

System.out.println("Ivr logged in");
}

/* (non-Javadoc)
* @see com.kmingle.template.BookMovieTicket#selectSource()
*/
@Override
public void selectSource() {

System.out.println("Ivr source selected");

}

/* (non-Javadoc)
* @see com.kmingle.template.BookMovieTicket#selectDestination()
*/
@Override
public void selectDestination() {

System.out.println("Ivr destination selected");

}

/* (non-Javadoc)
* @see com.kmingle.template.BookMovieTicket#makePayment()
*/
@Override
public void makePayment() {

System.out.println("Ivr payment done");

}

}

/**
 * Client Class
 */
package com.kmingle.template;

public class TemplateMethodDemo {

public static void main(String[] args) {

System.out.println("Book ticket online");
BookMovieTicket book_ticket_online = new BookTicketOnline();
book_ticket_online.bookTicket();

System.out.println("\nBook ticket through Phone(Ivr)");
BookMovieTicket book_ticket_ivr = new BookTicketIvr();
book_ticket_ivr.bookTicket();

}

}


OutPut :

Book ticket online
online logged in
online Source selected
online Destination selected
personal details entered from system
online payment done

Book ticket through Phone(Ivr)
Ivr logged in
Ivr source selected
Ivr destination selected
personal details entered from system
Ivr payment done

Total Pageviews