Click here to Skip to main content
15,886,518 members
Articles / Programming Languages / C#

Proxy Pattern Extending Open/Closed Principle to Avoid Declaring Singleton

Rate me:
Please Sign up or sign in to vote.
3.00/5 (1 vote)
12 Dec 2011CPOL3 min read 13.6K   14   3
Proxy pattern extending Open/Closed principle to avoid declaring singleton

Introduction

One of the disadvantages of using the Singleton pattern is the consumer class gets knowledge of its existence. There is no harm in having this knowledge, but it simultaneously brings the issue of tight coupling. This article will help you get independent of the singleton syntax, maintaining behavior.

Background

This article is based on industry wide used Design Patterns like Singleton, Proxy and assumes that the reader is quite comfortable with them. The approach mentioned in this article will work in scenarios where a singleton class has public methods without any public properties.

It might work as a remedy to the problem discussed in this StackOverflow thread.

If you have a Singleton with public properties, you can give a miss to this approach.

Using the Code

We all are comfortable with declaring a singleton in the following way (or something similar to this):

C#
public class ServiceProvider
{
   private static ServiceProvider instance = new ServiceProvider();

   private ServiceProvider()
   {
   }
    
   public static Instance
   {
     get
     {
       return instance;
     }
   }
   
   public int Foo()
   {
     // Do operation.
   }   
}

public class Consumer1
{
   public void DoAction1()
   {
     int i1 = serviceProvider.Instance.Foo();
   }
}

This code will work fine in all seasons provided the system will not require to change the singleton behavior of ServiceProvider. But there will always be a change which would make us scrap the singleton behavior. Naturally, we will then remove the singleton specific code from ServiceProvider and subsequently update the client side code.

This will need a lot of code change in the consumer side, violating the Open/Closed programming principle. E.g., declaring a local variable in the consumer if multiple methods are using the singleton functionality.

Replacing Singleton with Proxy

I have tried to solve this problem by bringing the Proxy pattern as a medium of communication between the consumer and the supposed to be Singleton service provider.

C#
public interface ISystemService
{
   int Foo();
}

internal class InternalServiceProvider : ISystemService
{
   public int Foo()
   {
     // Do some operation.
     return 1;
   }
}
public class ServiceProvider : ISystemService
{
   private static ISystemService proxy = new InternalServiceProvider();
   public int Foo()
   {
      return proxy.Foo();
   }
}

public class Consumer1
{
   public void DoAction1()
   {
     ISystemService serviceProvider = new ServiceProvider();
     int i1 = serviceProvider.Foo();
   }
}

public class Consumer2
{
   public void DoAction2()
   {
     ISystemService serviceProvider = new ServiceProvider();
     int i1 = serviceProvider.Foo();
   }
}

If you check the code carefully, you will find the client side is oblivious to the singleton behavior of ServiceProvider. The client side will always be required to instantiate the object before using it. Thus for the client, it will always work like a normal class.

Tomorrow, if we have to scrap the singleton behavior of ServiceProvider, we can easily achieve that by changing the code as:

  1. Converting the private static proxy property to private
  2. Instantiating proxy in a non-static instance specific constructor

Note that this change does not require any modification in the client side, allowing the client code to continue working in the same way.

C#
public class ServiceProvider : ISystemService
{
   private ISystemService proxy;

   public ServiceProvider()
   {
     proxy = new InternalServiceProvider();
   } 

   public int Foo()
   {
     return proxy.Foo();
   }   
}

How Does It Adhere to the Open/closed Principle?

Till now we have seen how we can switch on/off singleton behavior with minimal changes in code, but we haven't seen anything that makes it adhere to the Open/Closed principle, or does it already satisfy the Open/Closed principle requirements?

The answer is yes. We can change the behavior anytime by instantiating a different derived class of ISystemService in ServiceProvider, keeping the user oblivious to the change. Thus we also extend the advantages of the Open/Closed principle.

Points of Interest

This article provides a way to become independent of Singleton syntax, continuing to use its behavior. This solution may not fit all scenarios, but will be helpful in scenarios where no static data perseverance is required.

We can, by merging the Proxy pattern with the Open/Closed principle, make the system independent of Singleton syntax.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 3 Pin
stooboo9-Dec-11 2:40
stooboo9-Dec-11 2:40 
GeneralRe: My vote of 3 Pin
User-Rock9-Dec-11 2:49
User-Rock9-Dec-11 2:49 
GeneralRe: My vote of 3 Pin
stooboo9-Dec-11 3:02
stooboo9-Dec-11 3:02 
Hi
I had a look at that link and the consensus of opinion appears to agree with my comment
i.e. Use DI/IOC for this

I think it gives you far more flexibility
e.g.
you can choose in config whether to make it a singleton
you can choose in config the implementation
you can configure a factory to create the instance(s)

All that can be done by using IOC/DI and your classes will be 'open/closed' AND they will have 'single responsibility'

cheers
Stu

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.