Patterns: composition · 3 MIN READ

Proxy: control access to an existing operation

Make caching or lazy access preserve the caller’s expectations.

Make caching or lazy access preserve the caller’s expectations. Proxy stands in for a real subject and controls access, for example with caching, authorization or lazy construction. Trace the worked Go example, then compare the benefit with the cost before applying this design to your own project.

Structural pattern · A MAP OF THE IDEA

  1. Caller invokes the subject contract
  2. Proxy decides whether to delegate
  3. Real subject supplies the value

Useful when

  • Access needs caching, authorization or laziness
  • The stand-in can preserve the contract

Watch out

  • Freshness and invalidation are correctness rules
  • Caches need concurrency and size policies

Implementation & operation cost: Medium

Fit depends on the task

Small tool or CLI3/5
Domain-rich application4/5
Independent distributed services4/5

Editorial suitability, not benchmarks or a universal ranking. Styles describe different axes and can be combined.

01

The design decision

Proxy stands in for a real subject and controls access, for example with caching, authorization or lazy construction. It retains the subject’s interface. A cache is correct only when its key, lifetime and invalidation rules match the semantics of the underlying operation.

02

A complete Go example

Read this program from the entry point and follow the calls shown in the diagram. The output is included at the end so you can check the behavior without a compiler.

go
package main

import (
	"fmt"
)

type Lookup func(string) string

func Cached(next Lookup) Lookup {
	cache := make(map[string]string)
	return func(key string) string {
		if value, ok := cache[key]; ok {
			return value
		}
		value := next(key)
		cache[key] = value
		return value
	}
}

func main() {
	calls := 0
	lookup := Cached(func(key string) string { calls++; return "value:" + key })
	fmt.Println(lookup("go"))
	fmt.Println(lookup("go"))
	fmt.Println(calls)
}

// Output:
// value:go
// value:go
// 1
Read the code

The proxy invokes its subject once for the repeated key and returns the cached value on the second call. The closure is deliberately single-owner and unbounded for this tiny example; it is not a concurrent production cache.

03

Tradeoffs and the simpler alternative

Choose a TTL or invalidation policy for changing data and include authorization scope in cache keys where needed. Distinguish a cached empty value from a cache miss. If callers need fresh state, a direct lookup may be the only correct behavior.

TAKE THIS WITH YOU

Controls access while preserving the subject interface. Choose a TTL or invalidation policy for changing data and include authorization scope in cache keys where needed. Distinguish a cached empty value from a cache miss. If callers need fresh state, a direct lookup may be the only correct behavior.

Check your understanding

Which statement best describes Proxy: control access to an existing operation?

Go to the source

Progress stays in this browser. No account needed.