Exercise: Proxy
This exercise puts the Proxy pattern into code.
Scenario
A RealReportService generates reports on demand. Computing a report is expensive, so a
caching layer sits in front of it. The CachingReportServiceProxy wraps the real service and
implements the same ReportService interface. The first request for a key is a cache miss and
is forwarded to the real service; every subsequent request for the same key is a cache hit and
is served from the proxy's internal cache without touching the real service.
Commands
| Command | Behavior | Output |
|---|---|---|
["get", key] | Retrieve the report for key. On a miss, call the real service and cache the result. On a hit, read from cache. | MISS <key> -> report-<key> on a miss; HIT <key> -> report-<key> on a hit |
["calls"] | Return how many times the real service has been invoked so far. | Service calls: <n> |
7 get alpha get alpha get beta get alpha get gamma calls get beta
MISS alpha -> report-alpha HIT alpha -> report-alpha MISS beta -> report-beta HIT alpha -> report-alpha MISS gamma -> report-gamma Service calls: 3 HIT beta -> report-beta
The first get alpha is a miss: the proxy calls the real service, which returns report-alpha, and caches it. The second get alpha is a hit: the proxy reads from cache without calling the real service. get beta is another miss. The repeated get alpha and get gamma follow the same pattern. After five get commands, only three distinct keys (alpha, beta, gamma) were requested, so the real service was called exactly three times. The final get beta is a hit because it was already cached.
Your task
Create the CachingReportServiceProxy class so the commands produce the output shown above. The starter keeps the ReportService interface, the RealReportService (with its call counter), and the run_proxy dispatcher. It marks where to add the proxy class with a TODO comment listing the constructor signature, the get method's miss and hit behavior, and the call_count delegation.