Статический доступ к переменной нескольких экземпляров - PullRequest
4 голосов
/ 16 апреля 2010

У меня есть одноэлементный экземпляр, на который ссылаются в проекте, который работает как шарм. Это избавляет меня от необходимости передавать экземпляр объекта каждому маленькому классу в проекте. Однако теперь мне нужно управлять несколькими экземплярами предыдущей установки, а это означает, что шаблон синглтона разрывается, поскольку каждому экземпляру нужен собственный экземпляр синглтона.

Какие есть варианты для сохранения статического доступа к синглтону? Чтобы быть более конкретным, у нас есть наш игровой движок, и несколько компонентов и плагинов ссылаются на движок через статическое свойство. Теперь нашему серверу необходимо разместить несколько игровых экземпляров, каждый из которых имеет свой собственный движок, а это означает, что на стороне сервера шаблон синглтона ломается.

Я пытаюсь избежать всех классов, имеющих движок в конструкторе.

Редактировать: Двигатели не гарантированно работают в уникальном потоке. Каждый механизм имеет уникальный идентификатор, который можно использовать для идентификации экземпляра.

Ответы [ 4 ]

4 голосов
/ 16 апреля 2010

В этом случае шаблон Singleton ломается. Было удобно иметь единственное место, где весь ваш код мог бы получить экземпляр, но теперь вам нужно хранить несколько экземпляров. Тем не менее, вы правы, что очень раздражает проходить экземпляры контекста по всем цепочкам конструктора вашего дерева объектов. Одним из решений этой проблемы является использование платформы Inversion of Control, например Ninject . Это немного вложения в дизайн (поскольку привыкание к использованию IoC занимает некоторое время), но оно особенно хорошо помогает при решении этих проблем, когда вы хотите использовать внедрение зависимостей (передача GameEngine вашим различным классам), но не хочу писать кучу связующего кода, чтобы просто передать ссылки.

Тем не менее, если у вас есть только один подобный контекст (т. Е. Ваш синглтон только GameEngine), то, вероятно, проще всего добавить его во все ваши конструкторы.

3 голосов
/ 16 апреля 2010

Самое близкое, что вы можете сделать, это использовать атрибут ThreadStatic в вашей переменной экземпляра синглтона. Это будет поддерживать статическую семантику с точки зрения доступа, но у каждого потока будет свой экземпляр.

public class ThreadStaticSingleton
{
    [ThreadStatic]
    private static ThreadStaticSingleton instance;

    public static ThreadStaticSingleTon Instance
    {
        get 
        {
            if(instance == null) instance = new ThreadStaticSingleton();

            return instance;
        }
    }
}

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

Другими словами, это будет работать, если оба из следующих истинны:

  • Каждый игровой движок работает в своем собственном потоке
  • Каждый игровой движок только работает в одном потоке

В противном случае вам, вероятно, придется пойти по заводскому шаблону, где каждый движок передает какую-то идентифицирующую информацию (даже если это просто this) статической функции, чтобы получить экземпляр, а не просто использовать Instance собственность.

2 голосов
/ 16 апреля 2010

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

Есть и другие способы сделать это, не используя Singleton, но что-то вроде этого может сработать для вас (примечание: я не компилировал и не проверял это, но это могло бы дать вам начало).

public class MySingleton
{
    private static Dictionary<string, MySingleton> myInstances = new Dictionary<string, MySingleton>();

    private MySingleton()
    {
        // construct instance
    }

    // note: could also implement using an indexer
    // also note: this is not thread-safe, but you could add a lock around it
    public static MySingleton GetInstance(string key)
    {
        if (!myInstances.ContainsKey(key))
        {
            myInstances.Add(key, new MySingleton());
        }
        return myInstances[key];
    }

    // other methods
}
0 голосов
/ 16 апреля 2010

Я не уверен на 100%, что понял вопрос, но использование вами термина «экземпляр», по-видимому, предполагает, что каждый экземпляр объекта синглтона должен использоваться ровно одним экземпляром объекта клиентского класса. В этом случае, я бы сказал, просто получить экземпляр Singleton один раз для каждого экземпляра клиента и сохранить в переменной-члене.

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

...