The Problem
Some dependencies are expensive to call or should not be accessed directly every time. Remote object storage, payment providers, and search backends often need caching, access checks, or lazy connection setup before the real operation runs.
The Solution
Proxy keeps the same outward-facing contract as the real object, but interposes extra control before delegating. In Go, a proxy is often a wrapper struct that implements the same interface and adds caching, auth, throttling, or lazy initialization.
Structure
- Subject interface:
BlobReaderis the stable contract callers use. - Real subject:
S3BlobStoreperforms the underlying fetch. - Proxy:
CachedBlobStorecaches repeated reads before delegating. - Client: Reads through the interface and does not know whether the real object or proxy is behind it.
Implementation
This example fronts a blob store with a small caching proxy. The caller still depends on the BlobReader interface, but repeated reads avoid another simulated network fetch.
package main
import "fmt"
type BlobReader interface {
GetObject(key string) (string, error)
}
type S3BlobStore struct{}
func (S3BlobStore) GetObject(key string) (string, error) {
fmt.Printf("fetching %s from remote storage\n", key)
return "contents for " + key, nil
} Best Practices
- Keep the proxy contract identical to the real subject so callers stay unaware of the wrapper.
- Use a proxy for access control or optimization concerns that belong at the boundary.
- Invalidate or bound caches deliberately; stale proxy data is still a bug.
- Do not stack so many proxies that debugging the request path becomes opaque.
- If the wrapper adds optional behavior rather than access control, consider whether Decorator is the clearer term.
When to Use
- Access to a dependency needs caching, authorization, throttling, or lazy initialization.
- The real subject should remain untouched while callers keep the same interface.
- You want to enforce boundary policies consistently in one place.
When NOT to Use
- There is no meaningful control or optimization concern to add.
- A one-off helper around a single call site would be simpler.
- The wrapper changes the semantics so much that it is no longer the same subject.