Реализация наследуемого синглтон-класса в C#

Я обнаружил, что в C# вы можете реализовать класс Singleton следующим образом:

class Singleton
{

    private static Singleton _instance;

    public static Singleton Instance
    {
        get { return _instance ?? (_instance = new Singleton()); }
    }

    protected Singleton() { }
}

Который работает для экземпляров типа Singletonт.е.

var a = Singleton.Instance;
var b = Singleton.Instance;
Console.WriteLine(ReferenceEquals(a, b)); //Prints True.

Но что, если я хочу, чтобы производные классы Singleton также следовали шаблону Singleton, то есть:

class A:Singleton
{ ... }
A a = A.Instance;

В этом случае статический член Instance доступ к Singleton класс и создает Singleton пример, который не является целью. Кроме того, есть два основных проблемы с этим решением:

  • Производный класс может реализовать свой собственный конструктор и потерять шаблон Singleton.
  • Если есть другой случай Singleton тогда производный класс будет ссылаться на этот менее производный экземпляр

Мой вопрос: есть ли другой способ реализовать класс Singleton в C#, гарантирующий, что производный класс также будет singleton?

2 ответа

Решение

Не обращая внимания на обычное "Не используйте Singleton, посмотрите на свой дизайн". аргументы, вы могли бы реализовать его следующим образом (при условии, что у ваших производных классов есть конструкторы по умолчанию):

public abstract class Singleton<T> where T : class, new()
{
    private static T _instance;

    public static T GetInstance()
    {
        if(_instance == null)
            _instance = new T();
        return _instance;
    }
}

И выведем таким образом:

public class SingletonA : Singleton<SingletonA> { /* .... */ }
public class SingletonB : Singleton<SingletonB> { /* .... */ }

Но я действительно не защищаю этот синглтонный подход лично. У них есть свое (редкое) применение, но они могут оказаться более болезненными для задницы - превращаясь в прославленные глобальные переменные контейнеры.

Кроме того, помните о безопасности потоков.

Мой вопрос: есть ли другой способ реализовать класс Singleton в C#, гарантирующий, что производный класс также будет singleton?

Ну, вы можете иметь какую-то проверку внутри конструктора, которая:

  • Фактический тип this запечатан
  • Фактический тип this является прямым подклассом Singleton
  • Никакой другой экземпляр этого типа не был создан (сохраняя HashSet<Type>)

Однако это кажется довольно бессмысленным. Чего на самом деле должен достичь ваш базовый класс?

Одноэлементный шаблон легко реализовать правильно (чего, кстати, нет в вашем примере - он не безопасен для потоков), так зачем иметь базовый класс? Сам базовый класс не будет одноэлементным (потенциально может быть много экземпляров - по одному на каждый подкласс), так в чем же выгода?

Мне кажется, что "я одноэлементный для фактического типа объекта", во-первых, не является подходящей основой для наследования, и, честно говоря, я бы в любом случае старался избегать паттерна-одиночки.

Если вам действительно нужен базовый класс, это должно быть потому, что есть некоторые общие функциональные возможности, которые естественным образом наследуют все подклассы. Это вряд ли связано с тем, являются ли эти подклассы одиночными.

Другие вопросы по тегам