How to create your own Singleton from Scratch

One of the 23 described patterns by the Gang of Four is the Singleton Pattern, which says only one object of a particular class is ever created and all further references to objects of the singleton class refer to the same underlying instance.

As you may know, Ruby provides you a singleton module that you can include in your class, and magically your class is a singleton out of the box.

But let’s say for the sake of learning you want to create your own Singleton from scratch.

All the work done by the Ruby Singleton module is:

  • creates the class variable
  • initializes it with the singleton instance
  • creates the class level instance method
  • makes the new method private
  • prevents your class to be a Eager class
class MySingleton

  # This would cause a eager instantiation,
  # something that we want to avoid
  # @@instance = MySingleton.new

  def self.instance
    # this will prevent you to have a eager class
    @@instance ||= new
  end

  # and finally the `new` method becomes private
  private_class_method :new
end

An equivalent implementation of MySingleton would be, using the Ruby library:

require 'singleton'

class RubySingleton
  include Singleton
end

We can demonstrate this by running both implementation through the same test suite

require 'spec_helper'
require 'singleton/my_singleton'
require 'singleton/ruby_singleton'

shared_examples "a singleton" do
  it 'should not be a eager class' do
    # will return 1 if is a eager class and 0 if not
    ObjectSpace.each_object(described_class){}.should == 0
  end

  it 'should raise an error when calling the new method' do
    # `new` method is a private method
    expect {
      described_class.new
    }.to raise_error
  end

  it 'should always output the same instance' do
    singleton_instance = described_class.instance
    described_class.instance.should eql(singleton_instance)
    described_class.instance.class.should eql(singleton_instance.class)
  end
end

describe MySingleton do
  it_behaves_like "a singleton"
end

describe RubySingleton do
  it_behaves_like "a singleton"
end

You can learn more about ObjectSpace.

Happy coding!

photo of David Silva

Developer
comments powered by Disqus