Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
When to use
- To avoid dealing with inconsistent object when the object needs to be created over several steps.
- To avoid too many constructor arguments.
- To construct an object that should be immutable.
- To encapsulate the complete creation logic.
Intent
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
Components
- An Interface (or) Abstract class (public)
- Set of implementation subclasses (private)
- A Factory Method (public)
Structure
Implementation
1 Create an interface. Clients can code for this interface without worrying about the internal implementation..
package com.gaurav.factorymethod;
public interface Vehicle {
void design();
void manufacture();
}
2 Create a set of implementation subclasses. Constructors are protected to prohibit instantiations in clients modules using the 'new' operator.
package com.gaurav.factorymethod;
public class Car implements Vehicle {
Car() {
/* constructor is protected.
clients need to use the factory method */
}
@Override
public void design() {
System.out.println("Designing Car");
}
@Override
public void manufacture() {
System.out.println("Manufacturing Car");
}
}
package com.gaurav.factorymethod;
public class Truck implements Vehicle {
Truck() {
/* constructor is protected.
clients need to use the factory method */
}
@Override
public void design() {
System.out.println("Designing Truck");
}
@Override
public void manufacture() {
System.out.println("Manufacturing Truck");
}
}
package com.gaurav.factorymethod;
public class Motorcycle implements Vehicle {
Motorcycle() {
/* constructor is protected.
clients need to use the factory method */
}
@Override
public void design() {
System.out.println("Designing Motorcycle");
}
@Override
public void manufacture() {
System.out.println("Manufacturing Motorcycle");
}
}
3 Create a class with method 'getVehicle()'. Clients can use this method to create an object instead of using 'new' operator.
package com.gaurav.factorymethod;
public class VehicleFactory {
/* This is the factory method exposed to the client.
Client requests for an object by passing the type.
Client does not need to know about which & how object
is created internally.
*/
public Vehicle getVehicle(String vehicleType)
throws VehicleTypeNotFoundException {
if (vehicleType == null) {
return null;
}
Vehicle vehicle = null;
switch (vehicleType) {
case "car":
vehicle = new Car();
break;
case "truck":
vehicle = new Truck();
break;
case "motorcycle":
vehicle = new Motorcycle();
break;
default:
throw new VehicleTypeNotFoundException();
}
return vehicle;
}
}
4 The client code. Client knows only the factory method and the interface. Client code does not use 'new' hence decoupled from implementation.
package com.gaurav.client;
import java.util.Scanner;
import com.gaurav.factorymethod.Vehicle;
import com.gaurav.factorymethod.VehicleFactory;
import com.gaurav.factorymethod.VehicleTypeNotFoundException;
public class FactoryMethodClient {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String vehicleType = in.nextLine().toLowerCase();
/* Create a factory instance */
VehicleFactory factory = new VehicleFactory();
try {
/* Create an appropriate vehicle based on the input */
Vehicle vehicle = factory.getVehicle(vehicleType);
/* Design and manufacture the vehicle */
vehicle.design();
vehicle.manufacture();
} catch (VehicleTypeNotFoundException e) {
System.out.println("Invalid vehicle type entered!");
}
in.close();
}
}
Output
[input1]
MotorCycle
[output1]
Designing Motorcycle
Manufacturing Motorcycle
[input2]
Car
[output2]
Designing Car
Manufacturing Car
[input3]
Bus
[output3]
Invalid vehicle type entered!
Benefits
- Loose coupling allows changing the internals without impacting the customer code
- Factory method provides a single point of control for multiple products
- Number of instances and their reusability can be controlled with Singleton or Multiton
Drawbacks
An extra level of abstraction makes the code more difficult to read.
Real World Examples
Renting Vehicles. Customer needs to specify only the type of vehicle (car, truck, etc.) that is needed. Customer need not know about the internal details of the vehicle.
Software Example
- Memcache
- Filecache
- Code for SQL standard without worrying about the underlying DB
Java SDK Examples
java.util.Calendar.getInstance()
java.util.ResourceBundle.getBundle()
java.text.NumberFormat.getInstance()
java.nio.charset.Charset.forName()
java.util.EnumSet.of()
javax.xml.bind.JAXBContext.createMarshaller()
Difference between Abstract factory and Factory pattern?
TS;MR:
The Abstract Factory is a set of Factory Methods.
TL;DR:
With the Factory pattern, you produce instances of implementations (Apple, Banana, Cherry, etc.) of a particular interface -- say, IFruit.
With the Abstract Factory pattern, you provide a way for anyone to provide their own factory. This allows your warehouse to be either an IFruitFactory or an IJuiceFactory, without requiring your warehouse to know anything about fruits or juices.
Hope you like it. Would love to hear your thoughts on this design pattern.
Want to discuss more
Lets have a Coffee
Top comments (0)