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.
✓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