Logistic Management System - Factory Pattern Implementation
This is an implementation of the Factory design pattern for a logistics management system where different transport modes are created through a centralized factory, keeping the client code decoupled from concrete transport implementations.
Problem Statement
Building a logistics management system that supports multiple transport modes (Truck, Ship, Airplane). The challenge is to create the right transport object based on the delivery requirement without the client code directly instantiating concrete transport classes.
Key Challenge:
- Truck →
Delivering cargo by land in a box. - Ship →
Delivering cargo by sea in a container. - Airplane →
Delivering cargo by air in a cargo hold. - Client must never use
new TruckTransport(),new ShipTransport(), etc. directly
Class Diagram
+----------------------+
| LogisticsFactory |
+----------------------+
| + createTransport() |
+----------+-----------+
|
| (Creates)
v
+----------------------+
| Transport |
| (Interface) |
+----------------------+
| + deliver() |
+----------+-----------+
^
| (Implements)
+--------------------------+--------------------------+
| | |
+----------+----------+ +----------+----------+ +----------+----------+
| Truck | | Ship | | Airplane |
+---------------------+ +---------------------+ +---------------------+
| + deliver() | | + deliver() | | + deliver() |
+---------------------+ +---------------------+ +---------------------+
Implementation
package factory.logisticmanagementsystem;
public class LogisticManagementSystem {
/**
* Enum to define supported transport modes.
* Ensures type safety and prevents invalid string inputs.
*/
enum TransportType {
TRUCK,
SHIP,
AIRPLANE
}
/**
* Component Interface.
* Defines the contract all transport modes must follow.
*/
interface Transport {
void deliver();
}
/**
* Concrete Product for Land Delivery.
*/
static class TruckTransport implements Transport {
@Override
public void deliver() {
System.out.println("Delivering cargo by land in a box.");
}
}
/**
* Concrete Product for Sea Delivery.
*/
static class ShipTransport implements Transport {
@Override
public void deliver() {
System.out.println("Delivering cargo by sea in a container.");
}
}
/**
* Concrete Product for Air Delivery.
*/
static class AirTransport implements Transport {
@Override
public void deliver() {
System.out.println("Delivering cargo by air in a cargo hold.");
}
}
/**
* The Factory Class.
* This is the ONLY place where the new keyword is used to
* instantiate concrete transport classes.
* The client remains completely ignorant of which class is created.
*/
static class TransportFactory {
public Transport createTransport(TransportType transportType) {
return switch (transportType) {
case TRUCK -> new TruckTransport();
case SHIP -> new ShipTransport();
case AIRPLANE -> new AirTransport();
default -> throw new IllegalArgumentException(
"Unsupported Transport"
);
};
}
}
/**
* Main driver method.
* The client only interacts with the Factory and the Transport Interface.
* It never references TruckTransport, ShipTransport, or AirTransport directly.
*/
public static void main(String[] args) {
System.out.println("---- Logistics Management System ----");
TransportFactory factory = new TransportFactory();
Transport truck = factory.createTransport(TransportType.TRUCK);
truck.deliver();
Transport ship = factory.createTransport(TransportType.SHIP);
ship.deliver();
Transport airplane = factory.createTransport(TransportType.AIRPLANE);
airplane.deliver();
}
}
Key Features
- Factory Pattern: Centralizes transport object creation in one place
- Type Safety: Uses Enum for transport types instead of raw strings
-
Loose Coupling: Client only depends on the
Transportinterface, never on concrete classes - Single Responsibility: Factory handles creation, concrete classes handle delivery logic
- Open/Closed Principle: Add new transport modes without modifying existing code
- Extensible: New transport types require only a new class and a new Enum value
How It Works
-
Interface (Transport): Defines the
deliver()contract all transport modes must follow - Concrete Classes: Each class implements its own mode-specific delivery logic
-
Factory (TransportFactory): Takes a
TransportTypeEnum and returns the right transport object - Client (main): Only talks to the factory and the interface — never touches concrete classes directly