Creational PatternsAbstract Factory PatternMedium⏱️ ~3 min

Applying Abstract Factory to a Vehicle Parking System

Consider a parking lot system that supports different types of parking facilities: a standard parking lot and a valet parking service. Each facility type has its own ticket generation and fee calculation strategy, and these components must work together consistently.

Domain Requirements

First, standard parking uses printed tickets and calculates fees based on hourly rates. Second, valet parking uses digital tokens and includes additional service charges. Third, the system must support adding new parking facility types (like airport parking) without modifying existing client code.

Product Families

«interface»
ParkingTicket
+ getTicketId(): String
+ getEntryTime(): DateTime
+ print(): void
«interface»
FeeCalculator
+ calculate(duration): Money
+ getBreakdown(): String
Standard Family
PrintedTicket
- barcodeData: String
HourlyFeeCalculator
- hourlyRate: Money
Valet Family
DigitalToken
- qrCode: String
ValetFeeCalculator
- serviceCharge: Money

Factory Implementation

«interface»
ParkingFacilityFactory
+ createTicket(vehicle): ParkingTicket
+ createFeeCalculator(): FeeCalculator
StandardParkingFactory
+ createTicket(): PrintedTicket
+ createFeeCalculator(): HourlyFeeCalculator
ValetParkingFactory
+ createTicket(): DigitalToken
+ createFeeCalculator(): ValetFeeCalculator

Client Usage

class ParkingLot {
private factory: ParkingFacilityFactory
private tickets: Map<String, ParkingTicket>
private feeCalculator: FeeCalculator
constructor(factory: ParkingFacilityFactory) {
this.factory = factory
this.feeCalculator = factory.createFeeCalculator()
}
parkVehicle(vehicle: Vehicle): ParkingTicket {
ticket = factory.createTicket(vehicle)
tickets.put(ticket.getTicketId(), ticket)
return ticket
}
exitVehicle(ticketId: String): Money {
ticket = tickets.get(ticketId)
duration = calculateDuration(ticket.getEntryTime())
return feeCalculator.calculate(duration)
}
}

The ParkingLot class works with any factory type. To switch from standard to valet parking, simply pass ValetParkingFactory instead of StandardParkingFactory during initialization. The client code remains unchanged because it depends only on abstract interfaces.

Interview Tip: Explain that products from the same family (like PrintedTicket and HourlyFeeCalculator) are designed to work together, while mixing products from different families would create inconsistencies.

Extensibility

To add airport parking with monthly passes and flat-rate fees, create AirportParkingFactory, MonthlyPass, and FlatRateFeeCalculator. Existing code requires no modification. However, if you need to add a new product type (like ParkingReceipt), you must modify the abstract factory interface and all concrete factories, which is a known limitation of this pattern.

💡 Key Takeaways
Product families in parking domain include ticket generation and fee calculation strategies
StandardParkingFactory creates PrintedTicket and HourlyFeeCalculator that work together
ValetParkingFactory creates DigitalToken and ValetFeeCalculator with consistent behavior
Client code (ParkingLot) depends only on abstract factory and product interfaces
Adding new facility types requires no changes to existing code, only new factory and product classes
📌 Examples
1Standard parking with printed tickets and hourly rates
2Valet parking with digital tokens and service charges
3Airport parking with monthly passes and flat rates
← Back to Abstract Factory Pattern Overview
Applying Abstract Factory to a Vehicle Parking System | Abstract Factory Pattern - System Overflow