Decorator: how do you add caching, logging or retries without changing the class?
The gist
A Decorator wraps an object, implements the same protocol and adds behavior before or after forwarding the call: logging, caching, retries, metrics. The client gets any ProfileService and does not know whether it is the bare service or three layers of wrappers. Unlike inheritance, decorators are combined at runtime in any order, each one does a single job, and the original class stays untouched.
The rest of this answer, with code and interview follow-ups, is in the DevPrep app.
Read the full answer in DevPrep