docs: update multiton

This commit is contained in:
Ilkka Seppälä
2024-05-09 13:42:25 +03:00
parent de1dd7f82a
commit 6cc4525bc1
3 changed files with 63 additions and 66 deletions
+60 -61
View File
@@ -3,34 +3,32 @@ title: Multiton
category: Creational
language: en
tag:
- Instantiation
- Decoupling
- Instantiation
- Object composition
---
## Also known as
Registry
* Registry of Singletons
## Intent
Ensure a class only has a limited number of instances and provide a global point of access to them.
The Multiton pattern is a variation of the Singleton design pattern that manages a map of named instances as key-value pairs.
## Explanation
Real-world example
> The Nazgûl, also called ringwraiths or the Nine Riders, are Sauron's most terrible servants. By
> definition, there's always nine of them.
> The Nazgûl, also called ringwraiths or the Nine Riders, are Sauron's most terrible servants. By definition, there's always nine of them.
In plain words
> Multiton pattern ensures there are a predefined amount of instances available globally.
> Multiton pattern ensures there are a predefined amount of instances available globally.
Wikipedia says
> 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.
> 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.
**Programmatic Example**
@@ -39,46 +37,42 @@ Wikipedia says
```java
public enum NazgulName {
KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA
KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA
}
public final class Nazgul {
private static final Map<NazgulName, Nazgul> nazguls;
private static final Map<NazgulName, Nazgul> nazguls;
private final NazgulName name;
@Getter
private final NazgulName name;
static {
nazguls = new ConcurrentHashMap<>();
nazguls.put(NazgulName.KHAMUL, new Nazgul(NazgulName.KHAMUL));
nazguls.put(NazgulName.MURAZOR, new Nazgul(NazgulName.MURAZOR));
nazguls.put(NazgulName.DWAR, new Nazgul(NazgulName.DWAR));
nazguls.put(NazgulName.JI_INDUR, new Nazgul(NazgulName.JI_INDUR));
nazguls.put(NazgulName.AKHORAHIL, new Nazgul(NazgulName.AKHORAHIL));
nazguls.put(NazgulName.HOARMURATH, new Nazgul(NazgulName.HOARMURATH));
nazguls.put(NazgulName.ADUNAPHEL, new Nazgul(NazgulName.ADUNAPHEL));
nazguls.put(NazgulName.REN, new Nazgul(NazgulName.REN));
nazguls.put(NazgulName.UVATHA, new Nazgul(NazgulName.UVATHA));
}
static {
nazguls = new ConcurrentHashMap<>();
nazguls.put(NazgulName.KHAMUL, new Nazgul(NazgulName.KHAMUL));
nazguls.put(NazgulName.MURAZOR, new Nazgul(NazgulName.MURAZOR));
nazguls.put(NazgulName.DWAR, new Nazgul(NazgulName.DWAR));
nazguls.put(NazgulName.JI_INDUR, new Nazgul(NazgulName.JI_INDUR));
nazguls.put(NazgulName.AKHORAHIL, new Nazgul(NazgulName.AKHORAHIL));
nazguls.put(NazgulName.HOARMURATH, new Nazgul(NazgulName.HOARMURATH));
nazguls.put(NazgulName.ADUNAPHEL, new Nazgul(NazgulName.ADUNAPHEL));
nazguls.put(NazgulName.REN, new Nazgul(NazgulName.REN));
nazguls.put(NazgulName.UVATHA, new Nazgul(NazgulName.UVATHA));
}
private Nazgul(NazgulName name) {
this.name = name;
}
private Nazgul(NazgulName name) {
this.name = name;
}
public static Nazgul getInstance(NazgulName name) {
return nazguls.get(name);
}
public NazgulName getName() {
return name;
}
public static Nazgul getInstance(NazgulName name) {
return nazguls.get(name);
}
}
```
And here's how we access the `Nazgul` instances.
```java
// eagerly initialized multiton
LOGGER.info("Printing out eagerly initialized multiton contents");
LOGGER.info("KHAMUL={}", Nazgul.getInstance(NazgulName.KHAMUL));
LOGGER.info("MURAZOR={}", Nazgul.getInstance(NazgulName.MURAZOR));
@@ -89,18 +83,6 @@ LOGGER.info("HOARMURATH={}", Nazgul.getInstance(NazgulName.HOARMURATH));
LOGGER.info("ADUNAPHEL={}", Nazgul.getInstance(NazgulName.ADUNAPHEL));
LOGGER.info("REN={}", Nazgul.getInstance(NazgulName.REN));
LOGGER.info("UVATHA={}", Nazgul.getInstance(NazgulName.UVATHA));
// enum multiton
LOGGER.info("Printing out enum-based multiton contents");
LOGGER.info("KHAMUL={}", NazgulEnum.KHAMUL);
LOGGER.info("MURAZOR={}", NazgulEnum.MURAZOR);
LOGGER.info("DWAR={}", NazgulEnum.DWAR);
LOGGER.info("JI_INDUR={}", NazgulEnum.JI_INDUR);
LOGGER.info("AKHORAHIL={}", NazgulEnum.AKHORAHIL);
LOGGER.info("HOARMURATH={}", NazgulEnum.HOARMURATH);
LOGGER.info("ADUNAPHEL={}", NazgulEnum.ADUNAPHEL);
LOGGER.info("REN={}", NazgulEnum.REN);
LOGGER.info("UVATHA={}", NazgulEnum.UVATHA);
```
Program output:
@@ -116,25 +98,42 @@ Program output:
20:35:07.419 [main] INFO com.iluwatar.multiton.App - ADUNAPHEL=com.iluwatar.multiton.Nazgul@77556fd
20:35:07.419 [main] INFO com.iluwatar.multiton.App - REN=com.iluwatar.multiton.Nazgul@368239c8
20:35:07.420 [main] INFO com.iluwatar.multiton.App - UVATHA=com.iluwatar.multiton.Nazgul@9e89d68
20:35:07.420 [main] INFO com.iluwatar.multiton.App - Printing out enum-based multiton contents
20:35:07.420 [main] INFO com.iluwatar.multiton.App - KHAMUL=KHAMUL
20:35:07.420 [main] INFO com.iluwatar.multiton.App - MURAZOR=MURAZOR
20:35:07.420 [main] INFO com.iluwatar.multiton.App - DWAR=DWAR
20:35:07.420 [main] INFO com.iluwatar.multiton.App - JI_INDUR=JI_INDUR
20:35:07.421 [main] INFO com.iluwatar.multiton.App - AKHORAHIL=AKHORAHIL
20:35:07.421 [main] INFO com.iluwatar.multiton.App - HOARMURATH=HOARMURATH
20:35:07.421 [main] INFO com.iluwatar.multiton.App - ADUNAPHEL=ADUNAPHEL
20:35:07.421 [main] INFO com.iluwatar.multiton.App - REN=REN
20:35:07.421 [main] INFO com.iluwatar.multiton.App - UVATHA=UVATHA
```
## Class diagram
![alt text](./etc/multiton.png "Multiton")
![Multiton](./etc/multiton.png "Multiton")
## Applicability
Use the Multiton pattern when
* There must be a specific number of instances of a class, and they must be accessible to clients from
a well-known access point.
* A class must have named instances, but only one instance for each unique key.
* Global access to these instances is necessary without requiring global variables.
* You want to manage shared resources categorized by key.
## Known Uses
* Managing database connections in different contexts.
* Configuration settings for different environments in an application.
## Consequences
Benefits:
* Ensures controlled access to instances based on key.
* Reduces global state usage by encapsulating instance management within the pattern.
Trade-offs:
* Increased memory usage if not managed properly due to multiple instances.
* Potential issues with concurrency if not implemented with thread safety in mind.
## Related Patterns
[Singleton](https://java-design-patterns.com/patterns/singleton/): Multiton can be seen as an extension of the Singleton pattern where Singleton allows only one instance of a class, Multiton allows one instance per key.
[Factory Method](https://java-design-patterns.com/patterns/factory-method/): Multiton uses a method to create or retrieve instances, similar to how a Factory Method controls object creation.
## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI)
@@ -32,7 +32,7 @@ import lombok.extern.slf4j.Slf4j;
* the Multiton by passing an enumeration as a parameter.
*
* <p>There is more than one way to implement the multiton design pattern. In the first example
* {@link Nazgul} is the Multiton and we can ask single {@link Nazgul} from it using {@link
* {@link Nazgul} is the Multiton, and we can ask single {@link Nazgul} from it using {@link
* NazgulName}. The {@link Nazgul}s are statically initialized and stored in a concurrent hash map.
*
* <p>In the enum implementation {@link NazgulEnum} is the multiton. It is static and mutable
@@ -26,6 +26,7 @@ package com.iluwatar.multiton;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import lombok.Getter;
/**
* Nazgul is a Multiton class. Nazgul instances can be queried using {@link #getInstance} method.
@@ -34,6 +35,7 @@ public final class Nazgul {
private static final Map<NazgulName, Nazgul> nazguls;
@Getter
private final NazgulName name;
static {
@@ -56,8 +58,4 @@ public final class Nazgul {
public static Nazgul getInstance(NazgulName name) {
return nazguls.get(name);
}
public NazgulName getName() {
return name;
}
}