Showing posts with label Creational Design Pattern. Show all posts
Showing posts with label Creational Design Pattern. Show all posts

Friday, April 3, 2015

Builder Design Pattern

Design Pattern > Creational Design Pattern > Builder Design Pattern

As per GOF builder pattern “Separate the construction of a complex object from its representation so that the same construction process can create different representations.”
In this pattern client application will provide parameter (used to create complex object) to builder and builder will provide the final complex object to client.
Builder pattern solves the problem of increasing parameter in object constructor. For example suppose you have created a AnimalBuilder class which create different animal objects by assembling different parts of animal as parameters passed in constructor. Parameters can be animalType, head, tail, body, leg, animalVoice, colour etc.
Public class AnimalBuilder {
                public AnimalBuilder(String animalType, AnimalHead head, String tail, String body, String leg, Voice animalVoice, String colour){
                // initializing object
    }
}
This approach is error prone, you need to be very careful about passing the parameters while creating animal object. Since most of the parameters are of same type i.e. String, So tail can be passed instead of leg or body and created animal object would look like demon ;-) .
This can be resolved using builder pattern in which there is a builder class for each animal type (builder class assembles all the animal parts), this builder pass to a director class, which ultimately creates the final animal object.
the key terms in this pattern are –
  • Builder class that specifies an abstract interface for creating parts of a Product object.
  • ConcreteBuilder that constructs and puts together parts of the product by implementing the Builder interface. It defines and keeps track of the representation it creates and provides an interface for saving the product.
  • Director class that constructs the complex object using the Builder interface.
  • Product class that represents the complex object that is being built.
Java Implementation:
Assume that in toy factory assembly software assembles different animal parts and make a toy as final product. Implementation in builder pattern would include following classes:

/**
 * Product abstract class that holds the basic information for a product. It helps us build multiple products.
 */
package com.kmingle.builder;

public abstract class Animal{

       private String head;
       private String body;
       private String arm;
       private String leg;
       private String tail;
      
       public String getHead() {
              return head;
       }
       public void setHead(String head) {
              this.head = head;
       }
       public String getBody() {
              return body;
       }
       public void setBody(String body) {
              this.body = body;
       }
       public String getArm() {
              return arm;
       }
       public void setArm(String arm) {
              this.arm = arm;
       }
       public String getLeg() {
              return leg;
       }
       public void setLeg(String leg) {
              this.leg = leg;
       }
       public String getTail() {
              return tail;
       }
       public void setTail(String tail) {
              this.tail = tail;
       }
      
       public abstract void makeNoise();
      
       public void printAnimalDetails(){
              System.out.println(getHead());
              System.out.println(getBody());
              System.out.println(getArm());
              System.out.println(getLeg());
              System.out.println(getTail());
              makeNoise();
       }
}

/**
 * Product Class
 */
package com.kmingle.builder;

public class Lion extends Animal {
      
       @Override
       public void makeNoise() {
              System.out.println("Lion Roaring.......");
       }

}

/**
 * Product Class
 */
package com.kmingle.builder;

public class Swan extends Animal {

       @Override
       public void makeNoise() {

              System.out.println("Swan sound");
       }
      
}


/**
 * Abstract Builder class contains all the building methods to construct a general product (Animal)
 */
package com.kmingle.builder;

public abstract class AnimalBuilder {

       Animal animal;
       protected abstract void assembleAnimalHead();
       protected abstract void assembleAnimalBody();
       protected abstract void assembleAnimalArm();
       protected abstract void assembleAnimalLeg();
       protected abstract void assembleAnimalTail();
}

/**
 *  Concrete Builder Class
 */
package com.kmingle.builder;

public class LionBuilder extends AnimalBuilder {

       public LionBuilder(){
              animal = new Lion();
       }
      
       @Override
       protected void assembleAnimalHead() {
              animal.setHead("Lion's head assembled");
       }

       @Override
       protected void assembleAnimalBody() {
              animal.setBody("Lion's body assembled");
       }

       @Override
       protected void assembleAnimalArm() {
              animal.setArm("Lion's arm assembled");
       }

       @Override
       protected void assembleAnimalLeg() {
              animal.setLeg("Lion's leg assembled");
       }

       @Override
       protected void assembleAnimalTail() {
              animal.setTail("Lion's tail assembled");
       }

}


/**
 *  Concrete Builder Class
 */
package com.kmingle.builder;

public class SwanBuilder extends AnimalBuilder {

       public SwanBuilder(){
              animal = new Swan();
       }
      
       @Override
       protected void assembleAnimalHead() {
              animal.setHead("Swan's head assembled");
       }

       @Override
       protected void assembleAnimalBody() {
              animal.setBody("Swan's body assembled");
       }

       @Override
       protected void assembleAnimalArm() {
              animal.setArm("Swan's arm assembled");
       }

       @Override
       protected void assembleAnimalLeg() {
              animal.setLeg("Swan's leg assembled");
       }

       @Override
       protected void assembleAnimalTail() {
              animal.setTail("Swan's tail assembled");
       }

}


/**
 * Director Class actually drives the procedure with the necessary build parts and sequence of building an animal.
 */
package com.kmingle.builder;

public class AssemblyMachine {

       public void assembleAnimal(AnimalBuilder animalBuilder){
              animalBuilder.assembleAnimalHead();
              animalBuilder.assembleAnimalBody();
              animalBuilder.assembleAnimalArm();
              animalBuilder.assembleAnimalLeg();
              animalBuilder.assembleAnimalTail();
       }
}


/**
 * Client Class that creates dicrector and different animalbuilder objects to build final toy product
 */
package com.kmingle.builder;

public class Worker {

       public static void main(String[] args) {
              AssemblyMachine assemblyMachine = new AssemblyMachine();
             
              System.out.println("building Lion toy");
              LionBuilder lionBuilder = new LionBuilder();
              assemblyMachine.assembleAnimal(lionBuilder);
              lionBuilder.animal.printAnimalDetails();
             
              System.out.println("building Swan toy");
              SwanBuilder swanBuilder = new SwanBuilder();
              assemblyMachine.assembleAnimal(swanBuilder);
              swanBuilder.animal.printAnimalDetails();
       }

}

Out Put:
building Lion toy
Lion's head assembled
Lion's body assembled
Lion's arm assembled
Lion's leg assembled
Lion's tail assembled
Lion Roaring.......
building Swan toy
Swan's head assembled
Swan's body assembled
Swan's arm assembled
Swan's leg assembled
Swan's tail assembled
Swan sound


Now we have seen that as per Builder pattern definition AnimalBuilder Separates the construction of a complex object(Lion/Swan ) from its representation so that the same construction process(in AssemblyMachine) can create different representations(Lion/Swan etc).

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.

Total Pageviews