Post

Creational Design Patterns: Singleton Method

Purpose

The Singleton pattern ensures that a class has only one instance and provides global access to it. This is especially useful when only one object is required to coordinate actions throughout a system.

Explanation

  • Singleton restricts the instantiation of a class to a single object.
  • It provides a way to access its sole instance through a static method.
  • The instance is typically stored as a class variable, and the constructor is made private to prevent external instantiation.

Implementing Singleton Pattern in Ruby

In Ruby, the Singleton pattern can be implemented using the Singleton module provided by the Ruby standard library, or by manually controlling the instantiation process.

Let’s implement a Vehicle class as an example.

Using the Singleton Module

Ruby provides a Singleton module, which is the simplest way to create a singleton class.

Here’s how you can use it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
require 'singleton'

class Vehicle
  include Singleton

  attr_accessor :type, :model

  def initialize
    @type = "Car"
    @model = "Sedan"
  end

  def details
    "Vehicle Type: #{@type}, Model: #{@model}"
  end
end

vehicle1 = Vehicle.instance
vehicle2 = Vehicle.instance

puts vehicle1.details  
# Outputs: Vehicle Type: Car, Model: Sedan
puts vehicle2.details  
# Outputs: Vehicle Type: Car, Model: Sedan

puts vehicle1.object_id == vehicle2.object_id  
# Outputs: true, proving both are the same instance

Explanation:

The Singleton module takes care of everything: It ensures that the new method is private, provides an instance method, and controls the instantiation process.

Manually Implementing Singleton Pattern

You can also manually implement the Singleton pattern by controlling the instantiation process:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Vehicle
  @instance = nil

  private_class_method :new

  def self.instance
    @instance ||= new
  end

  attr_accessor :type, :model

  def initialize
    @type = "Car"
    @model = "Sedan"
  end

  def details
    "Vehicle Type: #{@type}, Model: #{@model}"
  end
end

vehicle1 = Vehicle.instance
vehicle2 = Vehicle.instance

puts vehicle1.details  
# Outputs: Vehicle Type: Car, Model: Sedan
puts vehicle2.details  
# Outputs: Vehicle Type: Car, Model: Sedan

puts vehicle1.object_id == vehicle2.object_id  
# Outputs: true, proving both are the same instance

Explanation:

  • The new method is made private to prevent direct instantiation.
  • The class has a class-level instance variable @instance that stores the single instance of the class.
  • The instance method checks if an instance already exists; if not, it creates one.

Key Points:

  • Global Access Point: The Singleton pattern allows controlled access to a single instance of a class.
  • Shared Resource: It is particularly useful when a single object needs to manage shared resources, such as a configuration manager or a logging system.
  • Thread Safety: In multi-threaded applications, ensure that the Singleton implementation is thread-safe, as two threads might simultaneously access the instance method and create two instances.

We just saw how Singleton Pattern can be implemented in Ruby using both built-in Singleton module and manual.

Happy Coding :)

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.