简体   繁体   中英

Two instances of a singleton needed

I had to extend my existing code with a Class B. The existing code uses a singleton in Library. Now Class B (which itself will be available as a singleton as is Class A) needs its own library instance...

I'm wondering what's the best way to extend the existing code (Class A, Library) such that I have to change the library as less as possible.

public class A 
{
    var lib = Library.Instance;

    public DoSomething()
    {
        lib.DoStuff();
    }    
}

public class B
{
    var lib = Library.Instance;  //wrong! needs its own instance

    public DoSomething()
    {
        lib.DoOtherStuff();
    }    
}

public class Library
{
    public static Library Instance
    {
        get
        {
            return _librarySingleton;
        }
    }

    //library internally uses singleton too!!
}

public static class MyProgram
{
    var a = new A();    //will be an singleton
    var b = new B();    //will be an singleton

    a.DoSomething();
    b.DoSomething();
}

There will never be another class. So two instances will be just fine.

Unfortunately the Singleton pattern really can't help you here as this pattern is specifically designed to return one and only one instance for the lifetime of the application.

Singletons are useful for certain cases like Logging, however they are generally avoided as they are notoriously difficult to mock out, test and extend.

If possible, I would recommend refactoring the above code to use the Inversion of Control Pattern and constructor injection of the dependency. This is achieved by creating an interface, say ILibrary and having two implementations.

These implementations can be created once and stored to emulate Singleton-like behaviour in a third helper class. A really good way of doing this is in an enterprise application is to utilise a Dependency Injection Container , which maintains the lifetime of instances (Singleton or Transient) and allows easy injection into constructors.

A code example using IoC/DI as a pattern would look like this:

public class A 
{
    private readonly ILibrary _library;

    public A(ILibrary library)
    {
        _library = library;
    }

    public DoSomething()
    {
        _library.DoStuff();
    }    
}

public class B
{
    private readonly ILibrary _library;

    public B(ILibrary library)
    {
        _library = library;
    }

    public DoSomething()
    {
        _library.DoStuff();
    }      
}

public interface ILibrary
{
    void DoStuff();
}

public class LibraryTypeOne : ILibrary
{
    void DoStuff()
    {
         Console.WriteLine("I am library type one");
    }
}

public class LibraryTypeTwo : ILibrary
{
    void DoStuff()
    {
         Console.WriteLine("I am library type two");
    }
}

public static class MyProgram
{
    var a = new A(new LibraryTypeOne());    // Note, you need to store
    var b = new B(new LibraryTypeTwo());    // these instances somewhere to 
                                            // share throughout the app

    a.DoSomething();
    b.DoSomething();
}

If your design will always be limited to 2 instances, you could provide a property Library.SecondInstance .

Anyway, you might want to take a look at the Multiton pattern as well.

DI container comes in very handy in these cases. Both A and B have a dependency on Libraray instance. Instead of creating that instance in those two classes, inject the dependency in to them. DI containers like Autofac maintain the single instance life time for you thus allowing you to inject these dependencies freely.

 public class Library
    {
        public Library()
        { }
        private static Library _secondInstance = new Library();
        private static Library _librarySingleton = new Library();
        public Library Second()
        {
            return _secondInstance;
        }
        public static Library Instance
        {
            get
            {
                return _librarySingleton;
            }
        }
        //library internally uses singleton too!!
    }

usage

 Library obj1 = Library.Instance;
 Library obj2= Library.Instance.Second();

Looks a bit readable to me

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM