|
| 1 | +--- |
| 2 | +layout: distill |
| 3 | +title: singleton pattern |
| 4 | +description: singleton pattern (C#) |
| 5 | +tags: code c# |
| 6 | +giscus_comments: true |
| 7 | +date: 2024-09-05 |
| 8 | +featured: false |
| 9 | +slug: singleton-pattern |
| 10 | + |
| 11 | +authors: |
| 12 | + - name: Andrei Gulin |
| 13 | + |
| 14 | +# Optionally, you can add a table of contents to your post. |
| 15 | +# NOTES: |
| 16 | +# - make sure that TOC names match the actual section names |
| 17 | +# for hyperlinks within the post to work correctly. |
| 18 | +# - we may want to automate TOC generation in the future using |
| 19 | +# jekyll-toc plugin (https://github.com/toshimaru/jekyll-toc). |
| 20 | +toc: |
| 21 | + - name: Introduction |
| 22 | + - name: Code Blocks |
| 23 | + - name: Thoughts |
| 24 | + - name: Learnt material |
| 25 | + |
| 26 | +# Below is an example of injecting additional post-specific styles. |
| 27 | +# If you use this post as a template, delete this _styles block. |
| 28 | +# _styles: > |
| 29 | +# .fake-img { |
| 30 | +# background: #bbb; |
| 31 | +# border: 1px solid rgba(0, 0, 0, 0.1); |
| 32 | +# box-shadow: 0 0px 4px rgba(0, 0, 0, 0.1); |
| 33 | +# margin-bottom: 12px; |
| 34 | +# } |
| 35 | +# .fake-img p { |
| 36 | +# font-family: monospace; |
| 37 | +# color: white; |
| 38 | +# text-align: left; |
| 39 | +# margin: 12px 0; |
| 40 | +# text-align: center; |
| 41 | +# font-size: 16px; |
| 42 | +# } |
| 43 | +--- |
| 44 | + |
| 45 | +## Introduction |
| 46 | + |
| 47 | +In this report, I will try to delve into the singleton pattern. How to implement it and when and where it is useful to apply. |
| 48 | + |
| 49 | +--- |
| 50 | + |
| 51 | +## References |
| 52 | + |
| 53 | +[Singleton pattern](https://refactoring.guru/design-patterns/singleton) |
| 54 | + |
| 55 | +--- |
| 56 | + |
| 57 | +## What does it do? |
| 58 | + |
| 59 | +1. The singleton pattern controls how many instances of a class can be created<d-footnote>To control access to shared resources, such as a database connection or a file.</d-footnote> |
| 60 | + |
| 61 | +2. Provide a global access point to that instance<d-footnote>With simple global variable that store important content, this content may be overwritten almost by everything, however singleton allows the access, but it as well protects from overwriting it</d-footnote> |
| 62 | + |
| 63 | + * Imagine that you created an object, but after a while decided to create a new one. Instead of receiving a fresh object, you’ll get the one you already created |
| 64 | + |
| 65 | + {% details note %} |
| 66 | + this behavior is impossible to implement with a regular constructor since a constructor call must always return a new object by design |
| 67 | + {% enddetails %} |
| 68 | + |
| 69 | + |
| 70 | +--- |
| 71 | + |
| 72 | +## Implementation |
| 73 | + |
| 74 | +1. Make the default constructor private, to prevent other objects from using the `new` operator with the Singleton class. |
| 75 | + |
| 76 | +2. Create a static creation method that acts as a constructor. Under the hood, this method calls the private constructor to create an object and saves it in a static field. All following calls to this method return the cached object. |
| 77 | + |
| 78 | + |
| 79 | + * If your code has access to the Singleton class, then it’s able to call the Singleton’s static method. So whenever that method is called, the same object is always returned. |
| 80 | + |
| 81 | +--- |
| 82 | + |
| 83 | +## Code example |
| 84 | + |
| 85 | +```c# |
| 86 | +// The Database class defines the `getInstance` method that lets |
| 87 | +// clients access the same instance of a database connection |
| 88 | +// throughout the program. |
| 89 | +class Database is |
| 90 | + // The field for storing the singleton instance should be |
| 91 | + // declared static. |
| 92 | + private static field instance: Database |
| 93 | + |
| 94 | + // The singleton's constructor should always be private to |
| 95 | + // prevent direct construction calls with the `new` |
| 96 | + // operator. |
| 97 | + private constructor Database() is |
| 98 | + // Some initialization code, such as the actual |
| 99 | + // connection to a database server. |
| 100 | + // ... |
| 101 | +
|
| 102 | + // The static method that controls access to the singleton |
| 103 | + // instance. |
| 104 | + public static method getInstance() is |
| 105 | + if (Database.instance == null) then |
| 106 | + acquireThreadLock() and then |
| 107 | + // Ensure that the instance hasn't yet been |
| 108 | + // initialized by another thread while this one |
| 109 | + // has been waiting for the lock's release. |
| 110 | + if (Database.instance == null) then |
| 111 | + Database.instance = new Database() |
| 112 | + return Database.instance |
| 113 | + |
| 114 | + // Finally, any singleton should define some business logic |
| 115 | + // which can be executed on its instance. |
| 116 | + public method query(sql) is |
| 117 | + // For instance, all database queries of an app go |
| 118 | + // through this method. Therefore, you can place |
| 119 | + // throttling or caching logic here. |
| 120 | + // ... |
| 121 | +
|
| 122 | +class Application is |
| 123 | + method main() is |
| 124 | + Database foo = Database.getInstance() |
| 125 | + foo.query("SELECT ...") |
| 126 | + // ... |
| 127 | + Database bar = Database.getInstance() |
| 128 | + bar.query("SELECT ...") |
| 129 | + // The variable `bar` will contain the same object as |
| 130 | + // the variable `foo`. |
| 131 | +``` |
| 132 | + |
| 133 | +--- |
| 134 | + |
| 135 | +## Pros and Cons of the Singleton Pattern |
| 136 | + |
| 137 | +### **Pros** |
| 138 | + |
| 139 | +- **Single Instance**: Ensures that a class has only one instance. |
| 140 | +- **Global Access**: Provides a global access point to that instance. |
| 141 | +- **Lazy Initialization**: The singleton object is only initialized when it's requested for the first time, saving resources. |
| 142 | + |
| 143 | +### **Cons** |
| 144 | + |
| 145 | +- **Violates Single Responsibility Principle**: The pattern solves two problems at once—controlling instance creation and providing global access. |
| 146 | +- **Masks Bad Design**: Can hide design issues, as components may become overly dependent on each other. |
| 147 | +- **Multithreading Issues**: In a multithreaded environment, special handling is required to avoid creating multiple singleton instances. |
| 148 | +- **Difficult to Test**: Unit testing can be challenging because many frameworks rely on inheritance for mocking. The private constructor of a singleton makes mocking difficult, and static methods can’t be easily overridden in most languages. |
| 149 | + |
0 commit comments