Singleton pattern: Difference between revisions

From Wikipedia, the free encyclopedia
Jump to navigation Jump to search
imported>TarnishedPath
m Per page move: Changed link from Class (computer programming) to Class (programming) (×2) using MovePlus
No edit summary
 
Line 1: Line 1:
{{Short description|Design pattern in object-oriented software development}}
{{Short description|Programming technique to restrict a class to one instance}}
[[File:Singleton UML class diagram.svg|thumb|A [[class diagram]] exemplifying the singleton pattern.]]
[[File:Singleton UML class diagram.svg|thumb|A [[class diagram]] exemplifying the singleton pattern.]]


Line 25: Line 25:
* Providing a [[static method]] that returns a [[Reference (computer science)|reference]] to the instance
* Providing a [[static method]] that returns a [[Reference (computer science)|reference]] to the instance
The instance is usually stored as a private [[static variable]]; the instance is created when the variable is initialized, at some point before when the static method is first called.
The instance is usually stored as a private [[static variable]]; the instance is created when the variable is initialized, at some point before when the static method is first called.
This [[C++23]] implementation is based on the pre-C++98 implementation in the book {{Citation needed|reason=the book is ambiguous here.|date=March 2024}}.


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Line 35: Line 33:
     Singleton() = default; // no public constructor
     Singleton() = default; // no public constructor
     ~Singleton() = default; // no public destructor
     ~Singleton() = default; // no public destructor
     inline static Singleton* instance = nullptr; // declaration class variable
     inline static Singleton* inst = nullptr; // declaration class variable
     int value;
     int value;
public:
public:
     // defines a class operation that lets clients access its unique instance.
     // defines a class operation that lets clients access its unique instance.
     static Singleton& getInstance() {
     static Singleton& instance() {
         if (!instance) {
         if (!inst) {
             instance = new Singleton();
             inst = new Singleton();
         }
         }
         return *instance;
         return *inst;
     }
     }
    
    
Line 49: Line 47:
     Singleton& operator=(const Singleton&) = delete("Copy assignment disabled");
     Singleton& operator=(const Singleton&) = delete("Copy assignment disabled");


     static void destroy() {
     static void reset() {
         delete instance;
         delete inst;
         instance = nullptr;
         inst = nullptr;
     }
     }


Line 60: Line 58:
     }
     }


     void setValue(int newValue) noexcept {
     void setValue(int v) noexcept {
         value = newValue;
         value = v;
     }
     }
};
};


int main() {
int main() {
     Singleton::getInstance().setValue(42);
     Singleton::instance().setValue(42);
     std::println("value = {}", Singleton::getInstance().getValue());
     std::println("value = {}", Singleton::instance().getValue()); // prints "value = 42"
     Singleton::destroy();
     Singleton::reset();
}
}
</syntaxhighlight>
</syntaxhighlight>


The program output is
This is an implementation of the Meyers singleton, so named after the author of ''More Effective C++'' by Scott Meyers due to his recommendation of this implementation.<ref>{{cite book |author=Scott Meyers |title=More Effective C++ |publisher=Addison Wesley |year=1997 |isbn=0-201-63371-X |pages= 146 ff}}</ref> The Meyers singleton has no destruct method. The program output is the same as above.
 
<syntaxhighlight lang="c++">
value=42
</syntaxhighlight>
 
This is an implementation of the Meyers singleton<ref>{{cite book |author=Scott Meyers |title=More Effective C++ |publisher=Addison Wesley |year=1997 |isbn=0-201-63371-X |pages= 146 ff}}</ref> in C++11. The Meyers singleton has no destruct method. The program output is the same as above.


<syntaxhighlight lang="Cpp">
<syntaxhighlight lang="Cpp">
Line 89: Line 81:
     int value;
     int value;
public:
public:
     static Singleton& getInstance() {
     static Singleton& instance() {
         static Singleton instance;
         static Singleton instance;
         return instance;
         return instance;
Line 99: Line 91:
     }
     }
    
    
     void setValue(int newValue) noexcept {
     void setValue(int v) noexcept {
         value = newValue;
         value = v;
     }
     }
};
};


int main() {
int main() {
     Singleton::getInstance().setValue(42);
     Singleton::instance().setValue(42);
     std::println("value = {}", Singleton::getInstance().getValue());
     std::println("value = {}", Singleton::instance().getValue()); // prints "value = 42"
}
</syntaxhighlight>
 
While the Meyers singleton is mostly unique to C++ due to C++'s function-local <syntaxhighlight lang="cpp" inline>static</syntaxhighlight> variables with lazy thread-safe initialization, it can still be emulated in other languages.
 
For example, in [[Java (programming language)|Java]], one can use the "initialization-on-demand holder" idiom:
 
<syntaxhighlight lang="java">
public class Singleton {
    private Singleton() {}
 
    private static class Holder {
        static final Singleton INSTANCE = new Singleton();
    }
 
    public static Singleton instance() {
        return Holder.INSTANCE;
    }
}
}
</syntaxhighlight>
</syntaxhighlight>
Line 112: Line 122:
=== Lazy initialization ===
=== Lazy initialization ===


A singleton implementation may use [[lazy initialization]] in which the instance is created when the static method is first invoked. In [[Multithreading (software)|multithreaded]] programs, this can cause [[Race condition|race conditions]] that result in the creation of multiple instances. The following [[Java_version_history#Java_5|Java 5+]] example<ref>{{Cite book|author=Eric Freeman, Elisabeth Freeman, Kathy Sierra, and Bert Bates|title=Head First Design Patterns|publisher=O'Reilly Media, Inc|date=October 2004|edition=First|chapter=5: One of a Kind Objects: The Singleton Pattern|page=182|isbn=978-0-596-00712-6|chapter-url=https://books.google.com/books?id=GGpXN9SMELMC&pg=PA182}}</ref> is a [[Thread safety|thread-safe]] implementation, using lazy initialization with [[double-checked locking]].
A singleton implementation may use [[lazy initialization]] in which the instance is created when the static method is first invoked. In [[Multithreading (software)|multithreaded]] programs, this can cause [[Race condition|race conditions]] that result in the creation of multiple instances. The following [[Java version history#Java 5|Java 5+]] example<ref>{{Cite book|author=Eric Freeman, Elisabeth Freeman, Kathy Sierra, and Bert Bates|title=Head First Design Patterns|publisher=O'Reilly Media, Inc|date=October 2004|edition=First|chapter=5: One of a Kind Objects: The Singleton Pattern|page=182|isbn=978-0-596-00712-6|chapter-url=https://books.google.com/books?id=GGpXN9SMELMC&pg=PA182}}</ref> is a [[Thread safety|thread-safe]] implementation, using lazy initialization with [[double-checked locking]].


<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
Line 120: Line 130:
     private Singleton() {}
     private Singleton() {}


     public static Singleton getInstance() {
     public static Singleton instance() {
         if (instance == null) {
         if (instance == null) {
             synchronized (Singleton.class) {
             synchronized (Singleton.class) {
Line 130: Line 140:
         return instance;
         return instance;
     }
     }
}
</syntaxhighlight>
In a manner similar to the Meyers singleton, one can use <code>System.Lazy<T></code> in [[C Sharp (programming language)|C#]] to use lazy initialization:<ref>{{Cite web|title=Lazy<T> Class|url=https://learn.microsoft.com/en-us/dotnet/api/system.lazy-1|publisher=Microsoft Learn|website=learn.microsoft.com|author=Microsoft Learn|access-date=6 July 2026}}</ref>
<syntaxhighlight lang="csharp">
using System;
public sealed class Singleton
{
    private static readonly Lazy<Singleton> _instance = new(() => new Singleton());
    public static Singleton Instance => _instance.Value;
    private Singleton() {}
}
}
</syntaxhighlight>
</syntaxhighlight>
Line 137: Line 162:


Singletons also violate the [[single-responsibility principle]] because they are responsible for enforcing their own uniqueness along with performing their normal functions.<ref name="button" />
Singletons also violate the [[single-responsibility principle]] because they are responsible for enforcing their own uniqueness along with performing their normal functions.<ref name="button" />
=== Avoidance through dependency injection ===
[[Dependency injection]] can be used to avoid the singleton pattern. The singleton pattern enforces a structural restriction of only one instance of a class, but dependency injection focuses on how dependencies are passed around, avoiding the necessity of objects to look up their own global state.<ref>{{Cite web|title=Dependency injection guidelines|url=https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection/guidelines|author=Microsoft Learn|website=learn.microsoft.com|publisher=Microsoft Learn|date=11 March 2026}}</ref>
For example, in the following example, the <code>OrderService</code> is tightly coupled to <code>DatabaseConnection</code>; the database cannot be swapped and a different instance cannot be used.
<syntaxhighlight lang="java">
// a concrete singleton class
class DatabaseConnection {
    private static DatabaseConnection instance;
    private DatabaseConnection() {
        // database resource initialization
    }
    public static synchronized DatabaseConnection instance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
    public void executeQuery(String sql) {
        System.out.printf("Executing: %s%n");
    }
}
// a tightly-coupled consumer class
class OrderService {
    public void placeOrder(String orderId) {
        // hardcoded dependency lookup makes this impossible to unit test
        DatabaseConnection db = DatabaseConnection.instance();
        db.executeQuery(String.format("INSERT INTO orders VALUES ('%s')"));
    }
}
</syntaxhighlight>
Dependency injection avoids asking how the database is created, or how many instances exist, and only asks for the <code>Database</code> [[Interface (object-oriented programming)|interface]] in its constructor:
<syntaxhighlight lang="java">
// an abstract interface
interface Database {
    void executeQuery(String sql);
}
// implement the concrete class (no singleton logic)
class SqlDatabase implements Database {
    @Override
    public void executeQuery(String sql) {
        System.out.println("Executing SQL: %s", sql);
    }
}
// the consumer class accepts dependency via constructor injection
class OrderService {
    private final Database db;
    // The dependency is injected from the outside
    public OrderService(Database db) {
        this.db = db;
    }
    public void placeOrder(String orderId) {
        db.executeQuery(String.format("INSERT INTO orders VALUES ('%s')", orderId));
    }
}
</syntaxhighlight>


== See also ==
== See also ==
* [[Initialization-on-demand holder idiom]]
* [[Initialization-on-demand holder idiom]]
* [[Multiton pattern]]
* [[Multiton pattern]]
* [[Dependency injection]]
* [[Software design pattern]]
* [[Software design pattern]]



Latest revision as of 05:25, 6 July 2026

Template:Short description

File:Singleton UML class diagram.svg
A class diagram exemplifying the singleton pattern.

In object-oriented programming, the singleton pattern is a software design pattern that restricts the instantiation of a class to a singular instance. It is one of the well-known "Gang of Four" design patterns, which describe how to solve recurring problems in object-oriented software.[1] The pattern is useful when exactly one object is needed to coordinate actions across a system.

More specifically, the singleton pattern allows classes to:[2]

  • Ensure they only have one instance
  • Provide easy access to that instance
  • Control their instantiation (for example, hiding the constructors of a class)

The term comes from the mathematical concept of a singleton.

Common uses

Singletons are often preferred to global variables because they do not pollute the global namespace (or their containing namespace). Additionally, they permit lazy allocation and initialization, whereas global variables in many languages will always consume resources.[1][3]

The singleton pattern can also be used as a basis for other design patterns, such as the abstract factory, factory method, builder and prototype patterns. Facade objects are also often singletons because only one facade object is required.

Logging is a common real-world use case for singletons, because all objects that wish to log messages require a uniform point of access and conceptually write to a single source.[4]

Implementations

Implementations of the singleton pattern ensure that only one instance of the singleton class ever exists and typically provide global access to that instance.

Typically, this is accomplished by:

The instance is usually stored as a private static variable; the instance is created when the variable is initialized, at some point before when the static method is first called.

import std;

class Singleton {
private:
    Singleton() = default; // no public constructor
    ~Singleton() = default; // no public destructor
    inline static Singleton* inst = nullptr; // declaration class variable
    int value;
public:
    // defines a class operation that lets clients access its unique instance.
    static Singleton& instance() {
        if (!inst) {
            inst = new Singleton();
        }
        return *inst;
    }
  
    Singleton(const Singleton&) = delete("Copy construction disabled");
    Singleton& operator=(const Singleton&) = delete("Copy assignment disabled");

    static void reset() {
        delete inst;
        inst = nullptr;
    }

    // existing interface goes here
    [[nodiscard]]
    int getValue() const noexcept {
        return value;
    }

    void setValue(int v) noexcept {
        value = v;
    }
};

int main() {
    Singleton::instance().setValue(42);
    std::println("value = {}", Singleton::instance().getValue()); // prints "value = 42"
    Singleton::reset();
}

This is an implementation of the Meyers singleton, so named after the author of More Effective C++ by Scott Meyers due to his recommendation of this implementation.[5] The Meyers singleton has no destruct method. The program output is the same as above.

import std;

class Singleton {
private:
    Singleton() = default;
    ~Singleton() = default;
    int value;
public:
    static Singleton& instance() {
        static Singleton instance;
        return instance;
    }
  
    [[nodiscard]]
    int getValue() const noexcept {
        return value;
    }
  
    void setValue(int v) noexcept {
        value = v;
    }
};

int main() {
    Singleton::instance().setValue(42);
    std::println("value = {}", Singleton::instance().getValue()); // prints "value = 42"
}

While the Meyers singleton is mostly unique to C++ due to C++'s function-local static variables with lazy thread-safe initialization, it can still be emulated in other languages.

For example, in Java, one can use the "initialization-on-demand holder" idiom:

public class Singleton {
    private Singleton() {}

    private static class Holder {
        static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton instance() {
        return Holder.INSTANCE;
    }
}

Lazy initialization

A singleton implementation may use lazy initialization in which the instance is created when the static method is first invoked. In multithreaded programs, this can cause race conditions that result in the creation of multiple instances. The following Java 5+ example[6] is a thread-safe implementation, using lazy initialization with double-checked locking.

public class Singleton {
    private static volatile Singleton instance = null;

    private Singleton() {}

    public static Singleton instance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

In a manner similar to the Meyers singleton, one can use System.Lazy<T> in C# to use lazy initialization:[7]

using System;

public sealed class Singleton
{
    private static readonly Lazy<Singleton> _instance = new(() => new Singleton());

    public static Singleton Instance => _instance.Value;

    private Singleton() {}
}

Criticism

Some consider the singleton to be an anti-pattern that introduces global state into an application, often unnecessarily. This introduces a potential dependency on the singleton by other objects, requiring analysis of implementation details to determine whether a dependency actually exists.[8] This increased coupling can introduce difficulties with unit testing.[9] In turn, this places restrictions on any abstraction that uses the singleton, such as preventing concurrent use of multiple instances.[9][10][11]

Singletons also violate the single-responsibility principle because they are responsible for enforcing their own uniqueness along with performing their normal functions.[9]

Avoidance through dependency injection

Dependency injection can be used to avoid the singleton pattern. The singleton pattern enforces a structural restriction of only one instance of a class, but dependency injection focuses on how dependencies are passed around, avoiding the necessity of objects to look up their own global state.[12]

For example, in the following example, the OrderService is tightly coupled to DatabaseConnection; the database cannot be swapped and a different instance cannot be used.

// a concrete singleton class
class DatabaseConnection {
    private static DatabaseConnection instance;

    private DatabaseConnection() {
        // database resource initialization
    }

    public static synchronized DatabaseConnection instance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }

    public void executeQuery(String sql) {
        System.out.printf("Executing: %s%n");
    }
}

// a tightly-coupled consumer class
class OrderService {
    public void placeOrder(String orderId) {
        // hardcoded dependency lookup makes this impossible to unit test
        DatabaseConnection db = DatabaseConnection.instance();
        db.executeQuery(String.format("INSERT INTO orders VALUES ('%s')"));
    }
}

Dependency injection avoids asking how the database is created, or how many instances exist, and only asks for the Database interface in its constructor:

// an abstract interface
interface Database {
    void executeQuery(String sql);
}

// implement the concrete class (no singleton logic)
class SqlDatabase implements Database {
    @Override
    public void executeQuery(String sql) {
        System.out.println("Executing SQL: %s", sql);
    }
}

// the consumer class accepts dependency via constructor injection
class OrderService {
    private final Database db;

    // The dependency is injected from the outside
    public OrderService(Database db) {
        this.db = db;
    }

    public void placeOrder(String orderId) {
        db.executeQuery(String.format("INSERT INTO orders VALUES ('%s')", orderId));
    }
}

See also

References

<templatestyles src="Reflist/styles.css" />

  1. ↑ a b Script error: No such module "citation/CS1".
  2. ↑ Script error: No such module "citation/CS1".
  3. ↑ Script error: No such module "citation/CS1".
  4. ↑ Script error: No such module "citation/CS1".
  5. ↑ Script error: No such module "citation/CS1".
  6. ↑ Script error: No such module "citation/CS1".
  7. ↑ Script error: No such module "citation/CS1".
  8. ↑ Script error: No such module "citation/CS1".
  9. ↑ a b c Script error: No such module "citation/CS1".
  10. ↑ Steve Yegge. Singletons considered stupid, September 2004
  11. ↑ Hevery, Miško, "Global State and Singletons", Clean Code Talks, 21 November 2008.
  12. ↑ Script error: No such module "citation/CS1".

Script error: No such module "Check for unknown parameters".

External links

Script error: No such module "Side box". Script error: No such module "Side box".

Template:Design Patterns Patterns