Explore the Multiton Pattern in C++ for managing a limited number of instances, with detailed implementation, use cases, and examples.
In the world of software design patterns, the Multiton pattern stands out as a powerful tool for managing a limited number of instances of a class. While the Singleton pattern ensures a single instance, the Multiton pattern allows for multiple instances, each identified by a unique key. This pattern is particularly useful in scenarios where multiple instances of a class are needed, but their number should be controlled and managed efficiently.
The intent of the Multiton pattern is to ensure that a class has a limited number of instances, each associated with a unique key. It provides a global point of access to these instances, ensuring that the same instance is returned for a given key.
Use the Multiton pattern when:
Let’s dive into the implementation of the Multiton pattern in C++. We’ll start by defining a class that manages instances using a static map to store and retrieve them based on a unique key.
1#include <iostream>
2#include <map>
3#include <memory>
4#include <mutex>
5#include <string>
6
7class Multiton {
8public:
9 using Ptr = std::shared_ptr<Multiton>;
10
11 // Static method to get the instance associated with a key
12 static Ptr getInstance(const std::string& key) {
13 std::lock_guard<std::mutex> lock(mutex_);
14 auto it = instances_.find(key);
15 if (it == instances_.end()) {
16 it = instances_.emplace(key, std::make_shared<Multiton>(key)).first;
17 }
18 return it->second;
19 }
20
21 // Method to demonstrate functionality
22 void show() const {
23 std::cout << "Instance with key: " << key_ << std::endl;
24 }
25
26private:
27 // Private constructor to prevent direct instantiation
28 Multiton(const std::string& key) : key_(key) {}
29
30 std::string key_;
31 static std::map<std::string, Ptr> instances_;
32 static std::mutex mutex_;
33};
34
35// Initialize static members
36std::map<std::string, Multiton::Ptr> Multiton::instances_;
37std::mutex Multiton::mutex_;
38
39int main() {
40 auto instance1 = Multiton::getInstance("First");
41 auto instance2 = Multiton::getInstance("Second");
42 auto instance3 = Multiton::getInstance("First");
43
44 instance1->show();
45 instance2->show();
46 instance3->show();
47
48 return 0;
49}
std::shared_ptr to manage their lifetimes automatically.In applications where different configurations are needed for different modules, the Multiton pattern can manage configuration instances, each identified by a module name.
1class Configuration {
2public:
3 static std::shared_ptr<Configuration> getConfig(const std::string& moduleName) {
4 return Multiton::getInstance(moduleName);
5 }
6
7 void setParameter(const std::string& param, const std::string& value) {
8 parameters_[param] = value;
9 }
10
11 std::string getParameter(const std::string& param) const {
12 auto it = parameters_.find(param);
13 return it != parameters_.end() ? it->second : "";
14 }
15
16private:
17 Configuration(const std::string& moduleName) : moduleName_(moduleName) {}
18
19 std::string moduleName_;
20 std::map<std::string, std::string> parameters_;
21};
For applications requiring multiple database connections, each identified by a connection string or database name, the Multiton pattern can manage these connections efficiently.
1class DatabaseConnection {
2public:
3 static std::shared_ptr<DatabaseConnection> getConnection(const std::string& dbName) {
4 return Multiton::getInstance(dbName);
5 }
6
7 void query(const std::string& sql) {
8 std::cout << "Executing query on database " << dbName_ << ": " << sql << std::endl;
9 }
10
11private:
12 DatabaseConnection(const std::string& dbName) : dbName_(dbName) {}
13
14 std::string dbName_;
15};
To better understand the Multiton pattern, let’s visualize it using a class diagram.
classDiagram
class Multiton {
+getInstance(key: string) : Ptr
-Multiton(key: string)
-key_: string
-instances_: map<string, Ptr>
-mutex_: mutex
}
class Ptr
Multiton --> Ptr : manages
Diagram Description: The diagram shows the Multiton class managing instances through a map, with each instance identified by a key. The getInstance method provides access to these instances.
Experiment with the Multiton pattern by modifying the code examples:
Remember, mastering design patterns is a journey. As you explore the Multiton pattern, consider how it fits into your software architecture. Keep experimenting, stay curious, and enjoy the process!