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.

No comments:

Total Pageviews