When to Use Singleton Design Pattern
- There must be one and only one instance of a class;
- The class must be accessible to clients;
- The class should not require parameter as part of its construction;
- and when creating the instance that is expensive, a Singleton can improve performance.
- Accessing to a File System (Logger, Database);
- Accessing to a Shared Resources
- Log-in Credentials
Problems | Description |
---|---|
Anti-pattern | It violates the Single Responsibility Principle. It introduces global state that spans all over the application. |
Not thread safe | The basic implementation of Singleton is not thread safe. Especially in web application. Locking the resource/singleton before instantiating would solve the problem. |
Difficult to test | Test doubles cannot be implemented. To test it, you need to test the actual class. |
The UML Class Diagram
Class/Interface | Description |
---|---|
Singleton | A private class which is responsible for creating and maintaining its own unique instance. |
Example
The sample code presented here is a File Logger sample that supports thread safe. A test to insure that only one instance will be created is also provided in this code.
The Project Structure
The Singleton File Logger UML Class Diagram
File Logger Mapping on Singleton Design Pattern
Singleton Design Pattern | Singleton File Logger |
---|---|
Singleton | FileLogger |
The Codes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
namespace SingletonDesignPattern.Singleton | |
{ | |
class FileLogger | |
{ | |
private static FileLogger _instance; | |
private static System.IO.StreamWriter TextFile = new System.IO.StreamWriter(Directory.GetCurrentDirectory() + "\\Log.txt", true); | |
private static object lockThis = new object(); | |
private FileLogger() { } | |
public static FileLogger Instance | |
{ | |
get | |
{ | |
//This will ensure the thread safe | |
lock (lockThis) { | |
Console.WriteLine("Singleton invoked."); | |
if (_instance == null) | |
{ | |
_instance = new FileLogger(); | |
Console.WriteLine("Singleton Initialized."); | |
} | |
return _instance; | |
} | |
} | |
} | |
public void WriteToFile(string text) | |
{ | |
Console.WriteLine("Writing to File..."); | |
TextFile.WriteLine(text); | |
} | |
public void CloseFile() | |
{ | |
TextFile.Close(); | |
TextFile.Dispose(); | |
} | |
} | |
} |
Program.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using SingletonDesignPattern.Singleton; | |
namespace SingletonDesignPattern | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var fileLogger = FileLogger.Instance; | |
fileLogger.WriteToFile("Singleton is awesome for Performance."); | |
fileLogger.WriteToFile("More from Singleton.."); | |
//Test for to see if another instance will be created. | |
//Singleton Initialized should be printed twice. | |
var fileLogger1 = FileLogger.Instance; | |
fileLogger1.WriteToFile("Using another instance..."); | |
fileLogger1.WriteToFile("More from another instance."); | |
fileLogger.CloseFile(); | |
fileLogger1.CloseFile(); | |
} | |
} | |
} |
The Output
If we look closely on the output, the FileLogger was invoke twice but it is only initialized once. Meaning there is only one instance despite assigning to different variables.
Ok. Thank you! Hope this is helpful.