Monday, September 8, 2014

Factory Design Pattern


Definition

Factory method design pattern is a creational design pattern used to provide a common interface which lets the sub classes decide which implementation is required at run time. It is also considered as an implementation of Invocation Of Control principle.

Intention
  1. Provides a common interface to create objects without exposing the instantiation logic to the client.
  2. Refers to the newly created object through a common interface which leads the client logic need not to be changed future for new type of objects.

Diagram




Components

Client :  Works as the framework class which uses the Factory to get the required product object. In return,   It receives an abstract type of the product object and uses that reference for further operations.

Factory: Is responsible to create the expected object of the concrete class and cast it into the abstract type. It returns the product as an abstraction to the client. Factory hides the implementation of the creation of the specified object from the client.

Abstraction: Abstract class or interface that Product classes implements.

Product: Concrete class that implements Abstraction. Client class uses this object type returned by Factory without knowing it.


There are flavors of this design pattern.

Simple Factory

E.g.

//Product - Abstract Type
public interface Vehicle {

    public void getEngine();

}

 //Vehicle Type Car - Concrete Class
public class Car implements Vehicle {

    @Override
    public void getEngine() {
        System.out.println("Starting a Car...");
    }

}

//Vehicle Type Bike - Concrete Class
public class Bike implements Vehicle {

    @Override
    public void getEngine() {

        System.out.println("Starting a Bike...");

    }

}

//Null Object representer
public class NoVehicleFound implements Vehicle {

    @Override
    public void getEngine() {
        System.out.println("No Vehicle to start...");
    }

}


  //Simple Factory method
public class VehicleFactory {

    public static Vehicle createVehicle(String vehicleType) {

        if ("Bike".equalsIgnoreCase(vehicleType)) {

            return new Bike();
        }

        else if ("Car".equalsIgnoreCase(vehicleType)) {
            return new Car();
        }

        else {
            return new NoVehicleFound();
        }

    }

}


 //Client
public class SimpleFactoryUser {

    public static void main(String[] args) {
    Vehicle vehicle = VehicleFactory.createVehicle("car");  
    vehicle.getEngine(); // output:  Starting a Car...

    Vehicle vehicle2 = VehicleFactory.createVehicle("bike");  
    vehicle2.getEngine(); //output: Starting a Bike...   
   
    }
   
}

The disadvantage of Simple Factory is when add a new product to the Factory, the Factory class logic has to be changed. This will violate Open Closed Principle, classes should be open to extend but close to modification.

To avoid this, Reflection can be used in Java. This approach will reduce the performance though.

Advanced Factory without Reflection.

//Factory class

public class VehicleFactory {

    private static VehicleFactory vehicleFactory;

    private VehicleFactory() {

    }

    public static VehicleFactory instance() {

        if (vehicleFactory == null) {

            synchronized (VehicleFactory.class) {
                if (vehicleFactory == null) {
                    vehicleFactory = new VehicleFactory();
                }
            }

        }

        return vehicleFactory;
    }

    private Map<String, Vehicle> registeredVedhicleTypes = new HashMap<String, Vehicle>();

    public void registerProduct(String type, Vehicle vehicle) {
        registeredVedhicleTypes.put(type, vehicle);
    }

    public Vehicle createProduct(String productID) {
        return ((Vehicle) registeredVedhicleTypes.get(productID))
                .createVehicle();
    }

}


//Products Bus class

public class Bus implements Vehicle {

    static {
        VehicleFactory.instance().registerProduct("Bus", new Bus());
    }
   
    @Override
    public Vehicle   createVehicle(){
        return new Bus();
      
    }




    @Override
    public void getEngine() {
   
        System.out.println("This is a Bus Engine");
      
    }
   
}

//Car class
public class Car implements Vehicle {

    static {
        VehicleFactory.instance().registerProduct("Car", new Car());
    }

    @Override
    public void getEngine() {

    System.out.println("This is a Car Engine");
    }

    @Override
    public Vehicle createVehicle() {
        return new Car();
      

    }

}

//Abstraction
public interface Vehicle {
   
    

    Vehicle createVehicle();

    void getEngine();
   

}


//Client
public class FactoryUser {

    static {
        try {

// Product classes must be loaded before registering it with Factory
            Class.forName("com.oo.concepts.Car"); 
            Class.forName("com.oo.concepts.Bus");
        } catch (ClassNotFoundException any) {
            any.printStackTrace();
        }
    }

    public static void main(String[] args)  {

        Vehicle vehicle1 = VehicleFactory.instance().createProduct("Car");
        vehicle1.createVehicle().getEngine();
        Vehicle vehicle2 = VehicleFactory.instance().createProduct("Bus");
        vehicle2.createVehicle().getEngine();

    }

}

Product classes could be loaded from external files such as xml and property files. Spring framework uses
this approach.

No comments: