The Singleton pattern ensures that only one instance of a class exists in a program and provides a global access point to that instance. In Ruby, the Singleton
module is available in the singleton
library, making it easy to implement.
Using the Singleton
Module
Ruby provides a built-in Singleton
module that ensures only one instance of a class is created.
Example: Implementing Singleton Class
require 'singleton'
class Logger
include Singleton
def log(message)
puts "[LOG]: #{message}"
end
end
# Getting the single instance
logger1 = Logger.instance
logger2 = Logger.instance
logger1.log("Application started")
# Checking if both instances are the same
puts logger1.object_id == logger2.object_id # true
Explanation:
include Singleton
ensures that only one instance ofLogger
can be created..instance
method provides the singleton instance.- Direct instantiation is prevented (
Logger.new
will raise an error).
Creating a Singleton Without the Singleton
Module
If you prefer not to use the Singleton
module, you can manually implement the Singleton pattern.
Example: Manual Singleton Implementation
class Configuration
@instance = nil
private_class_method :new # Prevents direct instantiation
def self.instance
@instance ||= new
end
def setting
"Dark Mode Enabled"
end
end
# Getting the singleton instance
config1 = Configuration.instance
config2 = Configuration.instance
puts config1.setting # "Dark Mode Enabled"
puts config1.object_id == config2.object_id # true
How It Works:
@instance ||= new
ensures that only one instance is created.private_class_method :new
prevents direct instantiation.- Only
Configuration.instance
can access the instance.
When to Use Singleton in Ruby?
Use a Singleton when: ✅ You need a single shared resource (e.g., configuration, logging, database connection).
✅ You want to control access to an object, ensuring only one instance exists.
✅ You need global access to an instance without passing it around manually.
Common Use Cases
- Logger Service
- Application Configuration
- Cache Storage
- Database Connection Management
Singleton vs. Global Variables
Feature | Singleton Pattern | Global Variable ($var ) |
---|---|---|
Encapsulation | Yes (Encapsulated in class) | No (Accessible everywhere) |
Control Over Instantiation | Yes (Only one instance allowed) | No (Can be reassigned anytime) |
Thread Safety | Safer with Singleton Module | Risky (Mutable state) |
Using a Singleton is generally safer than using global variables, as it provides better encapsulation and prevents accidental modifications.
Thread-Safe Singleton
The built-in Singleton
module ensures thread safety in Ruby. However, if implementing manually, you need to make it thread-safe.
Example: Thread-Safe Singleton
require 'thread'
class SafeSingleton
@instance = nil
@mutex = Mutex.new
private_class_method :new
def self.instance
@mutex.synchronize do
@instance ||= new
end
end
end
How It Works:
@mutex.synchronize
ensures that only one thread initializes the instance.- This prevents race conditions in multi-threaded applications.
Singleton with Lazy Initialization
In some cases, you might want to initialize the singleton only when needed.
Example: Lazy Singleton
class LazyLoader
@instance = nil
def self.instance
@instance ||= new
end
def load_data
puts "Loading data..."
end
end
# Instance is created only when first used
loader = LazyLoader.instance
loader.load_data
Why Use Lazy Initialization?
- Saves memory by not creating the instance until needed.
- Useful for performance optimization in applications.
Database Connection Pooling
Most web frameworks, like Ruby on Rails, Django, or Spring Boot, use the Singleton pattern for managing database connections.
How It Works:
- A single instance of a connection pool is created and shared across the application.
- The connection pool is responsible for managing database connections, ensuring they are reused rather than recreated, which reduces overhead.
- Ruby on Rails uses the
ActiveRecord::Base.connection
singleton to manage and provide database connections.
# Example in Rails
ActiveRecord::Base.connection.execute("SELECT * FROM users")
- The
ActiveRecord::Base.connection
is a Singleton, ensuring all parts of the application share the same connection object for efficiency.