Singleton pattern gives a way of ensuring that there is only a single instance of a particular object - but why has the singleton become an anti-pattern? Well, the main issue with singleton is that it becomes very difficult to test since it is very likely that it’s tightly coupled to a something within the system - it’s just the nature of the singleton pattern, since it has to be able to create itself, and in order to do so, it needs to be able to gather everything it depends on by itself - not to mention issues with thread-safety if not done right.

Singleton’s are quite convenient though, it makes it very easy to get an instance of an object that should be accessible throughout the entire application.

So, how do you make singleton pattern without the bad side-effects?

Take a look at ApplicationContext.cs in the Umbraco codebase.

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
32
33
34
35
36
37
38
39
40
41
42
/// <summary>
/// Constructor
/// </summary>
/// <param name="dbContext"></param>
/// <param name="serviceContext"></param>
/// <param name="cache"></param>
public ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache)
{
    if (dbContext == null) throw new ArgumentNullException("dbContext");
    if (serviceContext == null) throw new ArgumentNullException("serviceContext");
    if (cache == null) throw new ArgumentNullException("cache");
    _databaseContext = dbContext;
    _services = serviceContext;
    ApplicationCache = cache;
}

/// <summary>
/// A method used to set and/or ensure that a global ApplicationContext singleton is created.
/// </summary>
/// <param name="appContext">
/// The instance to set on the global application singleton
/// </param>
/// <param name="replaceContext">If set to true and the singleton is already set, it will be replaced</param>
/// <returns></returns>
/// <remarks>
/// This is NOT thread safe
/// </remarks>
public static ApplicationContext EnsureContext(ApplicationContext appContext, bool replaceContext)
{
    if (ApplicationContext.Current != null)
    {
        if (!replaceContext)
            return ApplicationContext.Current;
    }
    ApplicationContext.Current = appContext;
    return ApplicationContext.Current;
}

/// <summary>
/// Singleton accessor
/// </summary>
public static ApplicationContext Current { get; internal set; }

So in this solution, you allow the option to construct along with set and get for the current singleton. Sure, having a setter means that the globally available instance can be changed to a different object at run-time, but it makes itself obvious enough that it would be easy to spot the mistake.