Problem Statement
Design a system for devices that can have different combinations of capabilities.
Base capability — every device can:
- Tell whether it is plugged in (
isPluggedIn()) - Provide its current charging percentage (
getChargingPercentage())
Optional capabilities:
- Display — show a message on screen (
showMessage(msg)) - Speaker — play/speak a message (
speak(msg))
Different devices support different combinations. For example, a Tablet has base device functionality + Display + Speaker. A simple Battery Pack might only have base functionality.
Design the classes/interfaces so that adding a new capability or a new device type is clean and doesn't require modifying existing code.
Constraints
- A device may have any subset of the optional capabilities
- Adding a new capability should follow Open/Closed principle
- Avoid forcing devices to implement capabilities they don't have
What the Interviewer Expects
- Segregated interfaces (Interface Segregation Principle):
Deviceinterface →isPluggedIn(),getChargingPercentage()Displayinterface →showMessage()Speakerinterface →speak()
- Compose via multiple interface implementation —
Tablet implements Device, Display, Speaker. ABatteryPack implements Deviceonly. - Prefer composition over deep inheritance — don't build a tall class hierarchy. Each capability is an independent interface.
- The common mistake (and what to avoid): cramming everything into one fat interface, forcing devices to implement no-op methods. That violates ISP and leads to messy code.
- Clean client code — you can check
if (device instanceof Display)or use a capability registry.
Follow-ups
- How would you add a new "Camera" capability without touching existing classes?
- What if capabilities can be added/removed at runtime (dynamic composition)? (hint: decorator or component pattern)
- How would you query "give me all devices that can display AND speak"?
- What are the trade-offs between interface-based composition and a component/entity system?