Classifications of Factory Patterns
- Simple Factory
- Factory Method
- Abstract Factory
Pattern Details and Implementations
Simple Factory
A Simple Factory encapsulates object creation within a single class. Clients rely on a parameter passed to the factory to determine which concrete product subclass to instantiate, while interacting with the product through a shared interface.
Structural Components
| Component | Relationship | Responsibility |
|---|---|---|
| Abstract Product | Parent of Concrete Products | Declares the common interface for objects created by the factory |
| Concrete Product | Subclass of Abstract Product | Provides the specific implementation of the product |
| Factory | Invoked by the client | Returns a specific product instance based on input parameters |
Implementation Scenario
Consider a logistics system where goods can be transported by road or sea. A central dispatch factory can determine the appropriate vehicle based on the requested mode.
public class TransportCreator {
public static Transport arrangeDelivery(String mode) {
if ("ROAD".equalsIgnoreCase(mode)) {
return new Truck();
} else if ("SEA".equalsIgnoreCase(mode)) {
return new Ship();
}
throw new IllegalArgumentException("Unsupported transport mode: " + mode);
}
}
public interface Transport {
void deliver();
}
public class Truck implements Transport {
@Override
public void deliver() {
System.out.println("Delivering cargo by road.");
}
}
public class Ship implements Transport {
@Override
public void deliver() {
System.out.println("Delivering cargo by sea.");
}
}
// Client execution
public class DispatchSystem {
public static void main(String[] args) {
Transport roadTransport = TransportCreator.arrangeDelivery("ROAD");
roadTransport.deliver();
Transport seaTransport = TransportCreator.arrangeDelivery("SEA");
seaTransport.deliver();
}
}
Output:
Delivering cargo by road.
Delivering cargo by sea.
Factory Method
The Factory Method pattern defines an interface for creating objects but allows subclasses to alter the type of objects that will be created. It addresses the Open-Closed Principle violation in Simple Factory by deferring instantiation to concrete creator classes.
Structural Components
| Component | Relationship | Responsibility |
|---|---|---|
| Abstract Product | Parent of Concrete Products | Declares the common interface for objects created |
| Concrete Product | Subclass of Abstract Product | Provides the specific implementation of the product |
| Abstract Creator | Parent of Concrete Creators | Declares the factory method returning a product type |
| Concrete Creator | Subclass of Abstract Creator | Implements the factory method to return a specific product instance |
Implementation Scenario
If the logistics system needs to support air transport, modifying the existing dispatch class would violate the Open-Closed Principle. Instead, separate logistics subclasses define the vehicle instantiation.
public abstract class LogisticsOrganizer {
public abstract Transport createTransport();
}
public class RoadLogistics extends LogisticsOrganizer {
@Override
public Transport createTransport() {
return new Truck();
}
}
public class SeaLogistics extends LogisticsOrganizer {
@Override
public Transport createTransport() {
return new Ship();
}
}
public class AirLogistics extends LogisticsOrganizer {
@Override
public Transport createTransport() {
return new Airplane();
}
}
public interface Transport {
void deliver();
}
public class Truck implements Transport {
@Override
public void deliver() {
System.out.println("Delivering cargo by road.");
}
}
public class Ship implements Transport {
@Override
public void deliver() {
System.out.println("Delivering cargo by sea.");
}
}
public class Airplane implements Transport {
@Override
public void deliver() {
System.out.println("Delivering cargo by air.");
}
}
// Client execution
public class DispatchSystem {
public static void main(String[] args) {
LogisticsOrganizer seaLogistics = new SeaLogistics();
Transport seaTransport = seaLogistics.createTransport();
seaTransport.deliver();
LogisticsOrganizer airLogistics = new AirLogistics();
Transport airTransport = airLogistics.createTransport();
airTransport.deliver();
}
}
Output:
Delivering cargo by sea.
Delivering cargo by air.
Abstract Factory
The Abstract Factory pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. Each concrete factory corresponds to a specific product family.
Structural Components
| Component | Relationship | Responsibility |
|---|---|---|
| Abstract Product | Parent of Concrete Products | Declares the common interface for a product type |
| Concrete Product | Subclass of Abstract Product | Provides the specific implementation of the product |
| Abstract Factory | Parent of Concrete Factories | Declares creation methods for each abstract product type |
| Concrete Factory | Subclass of Abstract Factory | Implements creation methods to return specific family product instances |
Implementation Scenario
Expanding the logistics system, cargo requires not only a vehicle but also appropriate packaging. Road logistics use trucks and wooden crates, while sea logistics use ships and steel containers. An abstract factory can manage these product families cohesively.
public interface LogisticsFactory {
Transport createTransport();
Packaging createPackaging();
}
public class RoadLogisticsFactory implements LogisticsFactory {
@Override
public Transport createTransport() {
return new Truck();
}
@Override
public Packaging createPackaging() {
return new WoodenCrate();
}
}
public class SeaLogisticsFactory implements LogisticsFactory {
@Override
public Transport createTransport() {
return new Ship();
}
@Override
public Packaging createPackaging() {
return new SteelContainer();
}
}
public interface Transport {
void deliver();
}
public interface Packaging {
void pack();
}
public class Truck implements Transport {
@Override
public void deliver() {
System.out.println("Delivering by road.");
}
}
public class Ship implements Transport {
@Override
public void deliver() {
System.out.println("Delivering by sea.");
}
}
public class WoodenCrate implements Packaging {
@Override
public void pack() {
System.out.println("Packing in a wooden crate.");
}
}
public class SteelContainer implements Packaging {
@Override
public void pack() {
System.out.println("Packing in a steel container.");
}
}
// Client execution
public class DispatchSystem {
public static void main(String[] args) {
LogisticsFactory roadFactory = new RoadLogisticsFactory();
Transport roadTransport = roadFactory.createTransport();
Packaging roadPackaging = roadFactory.createPackaging();
roadTransport.deliver();
roadPackaging.pack();
LogisticsFactory seaFactory = new SeaLogisticsFactory();
Transport seaTransport = seaFactory.createTransport();
Packaging seaPackaging = seaFactory.createPackaging();
seaTransport.deliver();
seaPackaging.pack();
}
}
Output:
Delivering by road.
Packing in a wooden crate.
Delivering by sea.
Packing in a steel container.