Multiton
Multiton generalizes Singleton to one instance per key via a registry, suiting named shared resources. It inherits Singleton's global-state drawbacks plus unbounded-growth memory risk.
The Multiton pattern generalizes Singleton: instead of a single global instance, it maintains a map of keyed instances, guaranteeing that exactly one instance exists for each key. It solves the problem of needing one shared object per logical identity — one connection per database name, one logger per category, one configuration per environment — while reusing instances rather than recreating them.
How It Works
The class hides its constructor and holds a static map from key to instance. A static accessor, typically getInstance(key), looks up the key: if an instance exists it is returned; otherwise one is created, stored, and returned. The map acts as a registry that owns the lifetime of every instance. Keys can be strings, enums, or any hashable identity.
Like Singleton, the lookup-create step must be thread-safe to avoid creating duplicate instances for the same key under concurrency; a concurrent map with atomic compute-if-absent is the usual remedy.
When to Use It
Use Multiton when you need a controlled, bounded set of named shared instances and want a single access point keyed by identity. Examples include a registry of per-tenant caches, per-region service clients, or per-name resource managers where each name must map to one and only one object.
It carries the same caveats as Singleton, amplified: it is global, keyed state. In modern code a dependency-injection container with keyed or named registrations, or an explicit cache/registry object passed via DI, usually expresses the same intent with better testability and clearer ownership.
Trade-offs
Multiton ensures uniqueness per key, centralizes creation, and reuses expensive per-identity instances. It is convenient when many parts of a program must reach the same keyed object.
The drawbacks mirror Singleton's: hidden global state that hampers testing, possible memory growth if keys are unbounded or never evicted (a leak risk, since the registry pins every instance), and concurrency hazards in the registry. Because it can grow without limit, an eviction or lifecycle policy is often needed, blurring the line into a cache. Many teams prefer an explicit, injected registry over a static Multiton for these reasons.
Related Patterns
Multiton is a direct generalization of Singleton (a Singleton is a Multiton with one key). It is closely related to a keyed Factory and to a registry. Flyweight also maintains a pool of shared instances keyed by intrinsic state, but its goal is memory sharing of immutable data rather than identity-scoped uniqueness.
Example
An application needs one logger per subsystem. LoggerManager.getInstance("payments") returns the payments logger, creating it on first request and caching it in a concurrent map; later calls with the same key return the same logger so all payment logs share configuration and output. Requesting getInstance("auth") yields a distinct, single auth logger. The manager guarantees one logger per named subsystem.