Using Sequence Diagrams to Validate Patterns
Sequence diagrams become powerful when combined with design patterns, showing not just what pattern you chose, but how it actually works in your system.
1. Strategy Pattern in Parking Fee Calculation
When interviewer asks "How do you handle different pricing strategies?", draw sequence diagram showing runtime strategy selection:
:ExitTerminal → :FeeCalculator: calculateFee(ticket, vehicle)
:FeeCalculator → :FeeCalculator: selectStrategy(vehicleType)
[returns :HourlyRateStrategy for COMPACT]
:FeeCalculator → :HourlyRateStrategy: calculate(duration)
:HourlyRateStrategy → :PricingConfig: getHourlyRate()
:PricingConfig ⤶ :HourlyRateStrategy: rate
[compute: duration * rate]
:HourlyRateStrategy ⤶ :FeeCalculator: amount
:FeeCalculator → :Money: «create»(amount)
:FeeCalculator ⤶ :ExitTerminal: fee:Money
Pattern validation: Sequence shows FeeCalculator delegates to strategy interface, not concrete classes. Easy to add FlatRateStrategy or DynamicPricingStrategy without changing FeeCalculator code (Open-Closed Principle).
2. Observer Pattern in Parking Spot Notifications
When spot becomes available, notify waiting customers:
:Vehicle → :ParkingLot: exit(ticket)
:ParkingLot → :ParkingSpot: markAvailable()
:ParkingLot → :SpotAvailabilitySubject: notifyObservers(spotType)
loop for each observer
:SpotAvailabilitySubject → :WaitlistService: update(spotType)
:WaitlistService → :NotificationService: sendSMS(customer)
:SpotAvailabilitySubject → :DisplayBoard: update(spotType)
:DisplayBoard → :DisplayBoard: incrementAvailableCount()
end loop
Pattern validation: ParkingLot doesn't know about specific observers. WaitlistService and DisplayBoard react independently. Adding MobileAppObserver requires zero changes to ParkingLot.
Interview Tip: When you mention a pattern, draw mini sequence diagram showing the key interaction. This proves you understand the pattern deeply, not just memorized the name.
3. Chain of Responsibility in Vending Machine
Handling payment through multiple processors:
:Customer → :VendingMachine: selectProduct(item, payment)
:VendingMachine → :CashHandler: processPayment(payment)
[if payment is not cash]
:CashHandler → :CardHandler: processPayment(payment)
[if payment is not card]
:CardHandler → :MobilePayHandler: processPayment(payment)
[mobile payment succeeds]
:MobilePayHandler ⤶ :CardHandler: success
:CardHandler ⤶ :CashHandler: success
:CashHandler ⤶ :VendingMachine: paymentConfirmed
:VendingMachine → :Dispenser: dispenseProduct(item)
Pattern validation: Each handler tries to process or passes to next handler. Chain is extensible (add CryptocurrencyHandler) without modifying existing handlers.
4. Factory Pattern in Vehicle Creation
:EntryTerminal → :VehicleFactory: createVehicle(licensePlate, type)
[if type == MOTORCYCLE]
:VehicleFactory → :Motorcycle: «create»(licensePlate)
:Motorcycle ⤶ :VehicleFactory: motorcycle
[else if type == CAR]
:VehicleFactory → :Car: «create»(licensePlate)
:Car ⤶ :VehicleFactory: car
:VehicleFactory ⤶ :EntryTerminal: vehicle:Vehicle
:EntryTerminal → :ParkingLot: findSpot(vehicle)
Pattern validation: EntryTerminal works with Vehicle interface, doesn't care about concrete type. Factory encapsulates instantiation logic. Adding Truck only modifies factory, not clients.
5. Decorator Pattern in Fee Calculation
Adding surcharges and discounts:
:ExitTerminal → :BaseFeeCalculator: calculateFee(ticket)
:BaseFeeCalculator ⤶ :ExitTerminal: baseFee = $10
:ExitTerminal → :WeekendSurchargeDecorator: calculateFee(ticket)
:WeekendSurchargeDecorator → :BaseFeeCalculator: calculateFee(ticket)
:BaseFeeCalculator ⤶ :WeekendSurchargeDecorator: $10
[apply 20% surcharge: $10 * 1.2 = $12]
:WeekendSurchargeDecorator ⤶ :ExitTerminal: $12
:ExitTerminal → :MemberDiscountDecorator: calculateFee(ticket)
:MemberDiscountDecorator → :WeekendSurchargeDecorator: calculateFee(ticket)
:WeekendSurchargeDecorator ⤶ :MemberDiscountDecorator: $12
[apply 10% discount: $12 * 0.9 = $10.80]
:MemberDiscountDecorator ⤶ :ExitTerminal: finalFee = $10.80
Pattern validation: Decorators wrap each other, each adding behavior. Order matters (surcharge before discount). Can mix-and-match decorators at runtime.
Interview Tip: If you claim "I'll use Strategy pattern for pricing," interviewer might ask "Show me the sequence." Be ready to sketch how objects interact at runtime, proving the pattern actually simplifies your design.
Common Interview Question: Pattern Comparison
"Why use Strategy over if-else for pricing?" Draw both sequences:
Without Pattern
calculateFee() {
if (type == HOURLY)
// logic
else if (type == FLAT)
// logic
}
Violates Open-Closed, hard to test individual strategies
→
With Strategy
calculator.calculate()
→ strategy.calculate()
Each strategy isolated
Each strategy testable independently, new strategies don't modify calculator
The sequence diagram makes it obvious why Strategy is superior: delegation to pluggable component versus monolithic conditional logic.