State / Control• Patterns: State, Singleton, Observer
Traffic Signal
Easy
Problem Summary
Design a Traffic Signal Controller managing 4-way intersections with smooth Red-Green-Yellow cycles, dynamic traffic-density durations, and emergency vehicle preemption.
Functional Scope
- Manage 4 cardinal directions (North, South, East, West) at an intersection.
- Strict sequence transitions: Red -> Green -> Yellow -> Red without invalid conflicting states.
- Dynamic interval duration overrides based on sensor queue telemetry.
- Emergency preemption mode that immediately forces Green on the corridor and Red elsewhere.
- Thread-safe timer coordination and hardware light state reporting.
Entity-Relationship (ER) Schema
TrafficSignalController [1] <---> [1] SignalState TrafficSignalController [1] <---> [4] TrafficLight SignalState <|.. RedState SignalState <|.. GreenState SignalState <|.. YellowState SignalState <|.. EmergencyState
Design Approach
Apply the State pattern to eliminate complex nested switch-case logic across multiple signal transitions. Concrete state classes encapsulate transition rules and duration parameters, while the controller provides synchronized locks for preemptive emergency overrides.
Core Classes & Models
TrafficSignalController (Context Singleton coordinating intersection lights)TrafficLight (Represents physical light head with Red, Yellow, Green bulbs)SignalState (State interface with handleTransition and getDuration)RedState, GreenState, YellowState, EmergencyOverrideState (Concrete States)VehicleSensorObserver (Observer for dynamic queue monitoring)
Code Blueprint
129 lines/**
* Low-Level Design: Traffic Signal Controller
* Design Patterns Applied:
* - State Pattern: State transitions between Red, Green, and Yellow cycles
* - Singleton Pattern: Central intersection controller managing all corridor lights
* - Observer Pattern: Real-time sensor notifications for emergency and congestion
*/
import java.util.*;
enum SignalColor { RED, YELLOW, GREEN }
// --- [DESIGN PATTERN: Observer] Telemetry sensor for emergency vehicle approach ---
interface VehicleSensorListener {
void onEmergencyVehicleDetected(String laneId);
}
// --- [DESIGN PATTERN: State] State interface encapsulating transition behavior ---
interface SignalState {
void handle(TrafficSignal signal);
SignalColor getColor();
}
class RedState implements SignalState {
@Override
public void handle(TrafficSignal signal) {
signal.setState(new GreenState(), signal.getGreenDuration());
}
@Override
public SignalColor getColor() { return SignalColor.RED; }
}
class GreenState implements SignalState {
@Override
public void handle(TrafficSignal signal) {
signal.setState(new YellowState(), signal.getYellowDuration());
}
@Override
public SignalColor getColor() { return SignalColor.GREEN; }
}
class YellowState implements SignalState {
@Override
public void handle(TrafficSignal signal) {
signal.setState(new RedState(), signal.getRedDuration());
}
@Override
public SignalColor getColor() { return SignalColor.YELLOW; }
}
class TrafficSignal {
private final String id;
private SignalState state;
private int durationSeconds;
private final int redDuration, yellowDuration, greenDuration;
public TrafficSignal(String id, int red, int yellow, int green) {
this.id = id;
this.redDuration = red;
this.yellowDuration = yellow;
this.greenDuration = green;
this.state = new RedState();
this.durationSeconds = red;
}
public void setState(SignalState state, int duration) {
this.state = state;
this.durationSeconds = duration;
System.out.println("🚦 Signal [" + id + "] transitioned to " + state.getColor() + " for " + duration + "s");
}
public void triggerCycle() {
state.handle(this);
}
public void emergencyOverride() {
System.out.println("🚨 EMERGENCY OVERRIDE on Signal [" + id + "] -> Immediate GREEN corridor");
setState(new GreenState(), 60);
}
public String getId() { return id; }
public SignalColor getCurrentColor() { return state.getColor(); }
public int getRedDuration() { return redDuration; }
public int getYellowDuration() { return yellowDuration; }
public int getGreenDuration() { return greenDuration; }
}
// --- [DESIGN PATTERN: Singleton] Orchestrator coordinating full intersection lights ---
class IntersectionController implements VehicleSensorListener {
private static IntersectionController instance;
private final Map<String, TrafficSignal> signals = new LinkedHashMap<>();
public static synchronized IntersectionController getInstance() {
if (instance == null) instance = new IntersectionController();
return instance;
}
public void addSignal(TrafficSignal signal) {
signals.put(signal.getId(), signal);
}
public void simulateStep() {
System.out.println("\n--- Simulating Intersection Signal Change ---");
for (TrafficSignal s : signals.values()) {
s.triggerCycle();
}
}
@Override
public void onEmergencyVehicleDetected(String laneId) {
TrafficSignal sig = signals.get(laneId);
if (sig != null) sig.emergencyOverride();
}
}
public class Main {
public static void main(String[] args) {
IntersectionController intersection = IntersectionController.getInstance();
TrafficSignal northSouth = new TrafficSignal("North-South", 30, 5, 25);
TrafficSignal eastWest = new TrafficSignal("East-West", 25, 5, 30);
intersection.addSignal(northSouth);
intersection.addSignal(eastWest);
intersection.simulateStep();
intersection.simulateStep();
intersection.onEmergencyVehicleDetected("North-South");
}
}