Hubbry Logo
Multiton patternMultiton patternMain
Open search
Multiton pattern
Community hub
Multiton pattern
logo
8 pages, 0 posts
0 subscribers
Be the first to start a discussion here.
Be the first to start a discussion here.
Contribute something
Multiton pattern
Multiton pattern
from Wikipedia
UML diagram of the multiton
UML diagram of the multiton

In software engineering, the multiton pattern is a design pattern which generalizes the singleton pattern. Whereas the singleton allows only one instance of a class to be created, the multiton pattern allows for the controlled creation of multiple instances, which it manages through the use of a map.

Rather than having a single instance per application (e.g. the java.lang.Runtime object in the Java programming language) the multiton pattern instead ensures a single instance per key.

The multiton pattern does not explicitly appear as a pattern in the highly regarded object-oriented programming textbook Design Patterns.[1] However, the book describes using a registry of singletons to allow subclassing of singletons,[2] which is essentially the multiton pattern.[citation needed]

Description

[edit]

While it may appear that the multiton is a hash table with synchronized access there are two important distinctions. First, the multiton does not allow clients to add mappings. Secondly, the multiton never returns a null or empty reference; instead, it creates and stores a multiton instance on the first request with the associated key. Subsequent requests with the same key return the original instance. A hash table is merely an implementation detail and not the only possible approach. The pattern simplifies retrieval of shared objects in an application.

Since the object pool is created only once, being a member associated with the class (instead of the instance), the multiton retains its flat behavior rather than evolving into a tree structure.

The multiton is unique in that it provides centralized access to a single directory (i.e. all keys are in the same namespace, per se) of multitons, where each multiton instance in the pool may exist having its own state. In this manner, the pattern advocates indexed storage of essential objects for the system (such as would be provided by an LDAP system, for example). However, a multiton is limited to wide use by a single system rather than a myriad of distributed systems.

Drawbacks

[edit]

This pattern, like the Singleton pattern, makes unit testing far more difficult,[3] as it introduces global state into an application.

With garbage collected languages it may become a source of memory leaks as it introduces global strong references to the objects.

Implementations

[edit]

In Java, the multiton pattern can be implemented using an enumerated type, with the values of the type corresponding to the instances. In the case of an enumerated type with a single value, this gives the singleton pattern.

In C#, we can also use enums, as the following example shows:

using System;
using System.Collections.Generic;

public enum MultitonType
{
    Zero,
    One,
    Two
}

public class Multiton
{
    private static readonly Dictionary<MultitonType, Multiton> instances =
        new Dictionary<MultitonType, Multiton>();

    private MultitonType type;

    private Multiton(MultitonType type)
    {
        this.type = type;
    }

    public static Multiton GetInstance(MultitonType type)
    {
        // Lazy init (not thread safe as written)
        // Recommend using Double Check Locking if needing thread safety
        if (!instances.TryGetValue(type, out var instance))
        {
            instance = new Multiton(type);

            instances.Add(type, instance);
        }

        return instance;
    }

    public override string ToString()
    {
        return $"My type is {this.type}";
    }

    // Sample usage
    public static void Main(string[] args)
    {
        Multiton m0 = Multiton.GetInstance(MultitonType.Zero);
        Multiton m1 = Multiton.GetInstance(MultitonType.One);
        Multiton m2 = Multiton.GetInstance(MultitonType.Two);

        Console.WriteLine(m0);
        Console.WriteLine(m1);
        Console.WriteLine(m2);
    }
}

References

[edit]
[edit]
Revisions and contributorsEdit on WikipediaRead on Wikipedia
from Grokipedia
The Multiton pattern is a creational in that extends the by managing a limited number of instances of a class, each uniquely identified by a key, to provide controlled global access while avoiding redundant object creation. Unlike the singleton, which restricts a class to exactly one instance, the multiton employs a mapping structure—such as a or —to associate each instance with a specific identifier, ensuring that requests for the same key return the existing instance rather than creating a new one. This approach promotes and consistency in multi-instance scenarios. Key characteristics of the multiton include thread-safe instance retrieval, enforcement of instance uniqueness per key, and centralized management of the instance pool, often implemented through a static registry within the class itself. It differs from related patterns like the object pool, which recycles a fixed set of instances without key-based differentiation, by focusing on named or keyed access for context-specific reuse. The pattern is particularly useful in concurrent environments, where it supports synchronized access to shared resources, such as in file-sharing systems for managing tracker communications or modules. Applications of the multiton span domains like database management and (CAD) systems, where it facilitates quick loading of features or parts by caching instances keyed by identifiers, thereby maintaining and reducing computational overhead in multi-user settings. While not part of the original catalog, it has gained recognition in modern for handling scenarios requiring multiple, identifiable singletons, such as configuration managers or resource allocators in distributed applications.

Definition and Purpose

Core Concept

The Multiton pattern is a creational design pattern that serves as a generalization of the , permitting a controlled multiplicity of class instances where each is uniquely identified by a key, such as a or an value. This approach ensures that instances are created and managed deliberately, associating exactly one instance per distinct key to avoid unnecessary duplication while supporting a finite set of related objects. Instances managed by the Multiton are maintained in a central registry, often realized as a hash map or , which facilitates global access across the application and enforces the uniqueness constraint based on keys. By centralizing storage, the pattern prevents the direct instantiation of the class via constructors, routing all requests through a retrieval mechanism that checks for existing entries before creating new ones. This registry acts as the sole point of control, promoting consistency and resource sharing. The primary intent of the Multiton pattern is to enable efficient through restricted object creation, particularly for scenarios where multiple similar but keyed instances are needed without allowing arbitrary proliferation of objects. It addresses the limitations of unrestricted instantiation by providing a structured way to reuse pre-existing instances for repeated key requests, thereby optimizing performance in contexts like caching or configuration handling. The represents a special case of the Multiton, limited to a single instance under a fixed key. A basic pseudocode representation of instance retrieval in the Multiton pattern illustrates its mechanics:

function getInstance(key): if registry contains key: return registry[key] else: newInstance = createNewInstance(key) registry[key] = newInstance return newInstance

function getInstance(key): if registry contains key: return registry[key] else: newInstance = createNewInstance(key) registry[key] = newInstance return newInstance

This process—creating instances only upon first demand for a given key—ensures efficiency while upholding the pattern's invariants.

Key Characteristics

The Multiton pattern maintains several core invariants that distinguish it from standard object-oriented instantiation. A fixed or bounded number of class instances is enforced, preventing uncontrolled proliferation while allowing multiple instances based on predefined criteria. Each instance is uniquely tied to an immutable key, ensuring that requests for the same key always retrieve the identical object, thereby promoting consistency and predictability in . Access to these instances is provided through a global static method, which serves as the sole entry point for retrieval and acts as a centralized registry. Behaviorally, the pattern incorporates , where instances are created only upon the first request for a specific key rather than preemptively, optimizing resource usage by deferring allocation until necessary. The creation logic is fully encapsulated within the class itself, hiding the complexity of instance management from clients and centralizing control over the lifecycle of objects. This encapsulation often involves an internal map data structure to associate keys with instances, as referenced in foundational descriptions of the . In contrast to regular object creation, the Multiton pattern eliminates public constructors, routing all instantiation through the key-based factory method to enforce the bounded instance policy and prevent direct object spawning. This design ensures that clients cannot bypass the controlled access mechanism, maintaining the integrity of the instance pool. The plays a pivotal role in this architecture, typically implemented as an enum, string, or integer, which guarantees orthogonality by providing a distinct, non-overlapping identifier for each instance variant.

Relation to Other Patterns

Comparison with Singleton

The Singleton and Multiton patterns share fundamental similarities in their approach to creational control, both ensuring that instances of a class are created and managed in a controlled manner while providing a global access point for retrieval. The Multiton can be considered a direct generalization of the Singleton, where the latter operates with a fixed, implicit key (such as null or empty) that permits only a single instance. Key differences arise in their scope of instantiation: the Singleton strictly limits a class to exactly one instance, eliminating the need for any identification key and enforcing uniqueness across the application. In contrast, the Multiton supports the creation and management of multiple instances, each uniquely identified by a key, enabling greater flexibility for scenarios like resource pooling where several similar but distinct objects are required. This multiplicity in the Multiton enhances scalability by allowing controlled expansion beyond a single resource, whereas the Singleton's rigidity suits cases demanding absolute uniqueness. The Singleton is typically chosen over the Multiton when a truly unique global resource is essential, such as an application-wide configuration manager or a centralized logging service that must remain singular to maintain consistency. Historically, the Multiton emerged as a non-GoF specifically to overcome the limitations of the Singleton's single-instance constraint in situations requiring multiple analogous instances under controlled access.

Comparison with Flyweight

The Multiton and Flyweight patterns both utilize a central registry, often implemented as a factory or map, to manage and share instances based on keys, thereby minimizing redundant object creation and promoting efficient resource use. Despite this commonality, the patterns diverge significantly in their handling of state and instance management. The Flyweight pattern, classified as a structural design pattern in the Gang of Four catalog, relies on separating an object's intrinsic state—immutable data shared across instances, such as a glyph's font metrics—from its extrinsic state, which is context-dependent and passed at runtime, enabling fine-grained sharing of lightweight, immutable objects in memory-intensive applications like graphics systems. In comparison, the Multiton pattern, an extension of the creational Singleton pattern outside the original Gang of Four framework, maintains a predefined, fixed set of distinct instances keyed for uniqueness, without mandating state separation; these instances can be mutable and represent variations like different resource configurations. Flyweight is preferable over Multiton when dealing with vast numbers of nearly identical objects that benefit from extrinsic state parameterization, as in character rendering within text editors where shared intrinsic properties like shape and color reduce while allowing positional variability. Multiton, by contrast, suits scenarios requiring a controlled pool of unique, non-interchangeable instances without the overhead of state partitioning. Although Flyweight forms part of the seminal catalog as a , Multiton emerged later as a generalizing Singleton principles and is absent from that foundational text.

Benefits and Limitations

Advantages

The Multiton pattern enhances by restricting the creation of class instances to a predefined, controlled number, thereby mitigating memory bloat in resource-intensive scenarios such as connection pools or caching mechanisms where unbounded instantiation could lead to excessive . This controlled allocation is particularly beneficial in environments with limited resources, as it promotes reuse of existing instances keyed by unique identifiers, reducing the overhead associated with repeated object creation and garbage collection. By centralizing instance management through a registry or map, the Multiton pattern ensures consistency throughout the application, guaranteeing that all components access the identical set of instances for a given key and thereby preventing duplication, fragmented state management, and potential inconsistencies that could arise from uncoordinated object creation. This uniform access mechanism fosters reliable behavior across distributed or modular systems, similar to how the maintains consistency for a single instance but extended to handle multiple keyed variants. The pattern further supports , wherein instances are instantiated only upon the first request for a specific key, which optimizes application startup times and runtime performance by deferring unnecessary computations and allocations until they are explicitly required. Additionally, it provides strong encapsulation by abstracting the intricacies of instance tracking, validation, and retrieval behind a simple, uniform interface, thereby simplifying client code and reducing the on developers who interact with the managed instances.

Disadvantages

The Multiton pattern introduces additional complexity through the management of keys and the maintenance of an instance map, which can complicate code maintainability relative to direct object creation. This overhead arises from the need to handle registry logic, potentially leading to more intricate class designs that are harder to understand and extend. Furthermore, the pattern's reliance on global state amplifies this complexity, as it creates shared resources that must be carefully coordinated across the application. In multi-threaded applications, implementing the Multiton pattern necessitates mechanisms, such as locks or thread-safe collections, to prevent concurrent modifications to the instance map. These measures can create bottlenecks by enforcing serialized access, reducing throughput in high-concurrency scenarios. Without proper handling, race conditions may arise during instance creation or retrieval, further exacerbating reliability issues. The global state inherent in the Multiton pattern poses significant challenges for , as shared instances can persist across test executions, leading to unintended interference and non-deterministic outcomes. Testers often require explicit cleanup routines or advanced mocking techniques to reset the state between runs, increasing the effort and fragility of test suites. This vulnerability to side effects, akin to those in global shared buffers, makes isolation of components more difficult and can hinder overall test coverage. Regarding , the pattern risks unbounded growth if the set of keys is not explicitly limited, as each new key can spawn a persistent instance that remains referenced in the map and thus ineligible for garbage collection. This can result in excessive memory consumption over time, particularly in long-running applications where key proliferation occurs without eviction policies. In resource-constrained environments, such accumulation may degrade performance or lead to out-of-memory errors if not monitored.

Implementations and Applications

General Implementation Approach

The general implementation approach for the Multiton pattern follows a structured to manage a controlled set of instances, each associated with a , extending the principles of the to support multiple keyed instances while ensuring global access and preventing redundant creation. This language-agnostic blueprint emphasizes encapsulation, , and centralized control through a registry mechanism. A foundational step is to define a private static (or equivalent associative ) within the class to store key-instance pairs. This acts as the central registry, enabling efficient lookup, storage, and retrieval of instances based on their identifying keys, which could be strings, enums, or other immutable types. The is typically initialized as empty to support on-demand population, aligning with characteristics of the pattern. The core access mechanism involves providing a public static factory method that accepts a key parameter. This method first queries the for an existing instance corresponding to the key; if none is found, it invokes the private constructor to create a new instance, associates it with the key, and adds the pair to the before returning the instance. If an instance already exists, it is simply retrieved and returned, ensuring that only one instance per key is ever created. To enforce exclusivity, all class constructors must be declared private, prohibiting direct instantiation from client and routing all requests through the factory method. This step guarantees thread-safe access in concurrent environments if the and method are appropriately synchronized, though basic implementations may require additional locking for production use. To address robustness, edge cases must be handled explicitly in the factory method, such as validating the input key and throwing an exception (e.g., for null or malformed keys) to prevent invalid entries in the registry. Optional cleanup functionality can include a static method to remove a specific instance from the map by key, facilitating resource reclamation in scenarios where instances are dynamically managed or when application lifecycle demands it.

Language-Specific Examples and Use Cases

In , the Multiton pattern can be implemented using a ConcurrentHashMap to manage instances keyed by an enum for and inherent , as Java enums ensure singleton-like behavior per value. This approach allows lazy or preloaded instantiation while avoiding concurrent modification issues.

java

import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public final class Multiton { private enum Key { TYPE_A, TYPE_B, TYPE_C } private static final Map<Key, Multiton> instances = new ConcurrentHashMap<>(); private final Key key; private Multiton(Key key) { this.key = key; } public static Multiton getInstance(Key key) { return instances.computeIfAbsent(key, Multiton::new); } @Override public String toString() { return "Multiton instance for key: " + key; } }

import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public final class Multiton { private enum Key { TYPE_A, TYPE_B, TYPE_C } private static final Map<Key, Multiton> instances = new ConcurrentHashMap<>(); private final Key key; private Multiton(Key key) { this.key = key; } public static Multiton getInstance(Key key) { return instances.computeIfAbsent(key, Multiton::new); } @Override public String toString() { return "Multiton instance for key: " + key; } }

This code lazily creates up to three instances based on the enum keys, demonstrating controlled multiplicity. The computeIfAbsent method handles thread-safe insertion atomically. In C#, the pattern employs a ConcurrentDictionary<TKey, Instance> with lazy initialization using GetOrAdd to ensure thread safety during instance creation, minimizing contention for subsequent accesses. The method atomically retrieves or adds the instance for a given key.

csharp

using System; using System.Collections.Concurrent; public class Multiton<TKey> { private static readonly ConcurrentDictionary<TKey, Multiton<TKey>> instances = new ConcurrentDictionary<TKey, Multiton<TKey>>(); private readonly TKey key; private Multiton(TKey key) { this.key = key; } public static Multiton<TKey> GetInstance(TKey key) { return instances.GetOrAdd(key, k => new Multiton<TKey>(k)); } public override string ToString() { return $"Multiton instance for key: {key}"; } }

using System; using System.Collections.Concurrent; public class Multiton<TKey> { private static readonly ConcurrentDictionary<TKey, Multiton<TKey>> instances = new ConcurrentDictionary<TKey, Multiton<TKey>>(); private readonly TKey key; private Multiton(TKey key) { this.key = key; } public static Multiton<TKey> GetInstance(TKey key) { return instances.GetOrAdd(key, k => new Multiton<TKey>(k)); } public override string ToString() { return $"Multiton instance for key: {key}"; } }

Here, GetInstance atomically retrieves or creates the instance, supporting keys like strings or enums. In Python, a simple uses a for the registry with a class method for access, suitable for single-threaded or synchronized environments.

python

class Multiton: _instances = {} def __new__(cls, key): if key not in cls._instances: cls._instances[key] = super(Multiton, cls).__new__(cls) return cls._instances[key] def __init__(self, key): self.key = key def __str__(self): return f"Multiton instance for key: {self.key}"

class Multiton: _instances = {} def __new__(cls, key): if key not in cls._instances: cls._instances[key] = super(Multiton, cls).__new__(cls) return cls._instances[key] def __init__(self, key): self.key = key def __str__(self): return f"Multiton instance for key: {self.key}"

This creates instances lazily on first access by key. For thread safety, a lock can be added around the dictionary check and assignment. The Multiton pattern applies to scenarios requiring controlled instances per identifier, such as managing database connection pools keyed by configuration profiles, where each profile (e.g., development vs. production) maintains a distinct pool to optimize . Similarly, it suits caching computed results by input parameters, ensuring a single cache entry per unique parameter set to avoid redundant calculations. For simulating hardware resources like printers in a network, instances can be keyed by device IDs, limiting creation to available hardware while enabling shared access. In game development, a real-world application involves managing a fixed set of enemy types keyed by difficulty level, such as easy, medium, or hard variants, to enforce resource limits and reuse behaviors efficiently across levels.
Add your contribution
Related Hubs
Contribute something
User Avatar
No comments yet.