Как избежать статических переменных с помощью Singleton - PullRequest
7 голосов
/ 01 ноября 2011

Мой коллега сказал мне, что я никогда не должен использовать статические переменные, потому что если вы меняете их в одном месте, они меняются везде.Он сказал мне, что вместо использования статических переменных я должен использовать Singleton.Я знаю, что синглтон предназначен для ограничения количества экземпляров одного класса одним.Как Singleton может помочь мне со статическими переменными?

Ответы [ 6 ]

5 голосов
/ 01 ноября 2011

Один способ использовать синглтон (поднято с http://msdn.microsoft.com/en-us/library/ff650316.aspx)

using System;

public class Singleton
{
   private static Singleton instance;

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null)
         {
            instance = new Singleton();
         }
         return instance;
      }
   }

   /// non-static members
   public string Foo { get; set; }        

}

Тогда

var foo = Singleton.Instance.Foo;
Singleton.Instance.Foo = "Potential thread collision here.";

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

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

public static class Foo
{
  public static string Bar
  {
    get { /// retrieve Bar from the db }
    set { /// update Bar in the db }
  }
}
3 голосов
/ 24 апреля 2017

Давайте рассмотрим ваши заявления по одному:

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

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

Он сказал мне, что вместо использования статических переменных я должен использовать Singleton.

Это нехорошо global совет.Статические переменные и синглтоны не конкурируют друг с другом и не заменяют друг друга.Singleton - это экземпляр класса, управляемый таким образом, что можно создать только один экземпляр.Статическая переменная аналогично привязана точно к одному (статическому) экземпляру класса, но может быть назначена не только экземпляром класса, но и любым типом данных, например скаляром.В действительности, чтобы эффективно использовать шаблон синглтона, вы должны сохранить его в статической переменной.Невозможно «использовать синглтон вместо статической переменной».

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

Я знаю, что синглтон предназначен дляограничение количества экземпляров одного класса одним.Как Singleton может помочь мне со статическими переменными?

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

Я также хотел бы отметить, чтодругие ответы, данные до сих пор, имеют проблемы с безопасностью потоков.Ниже приведены некоторые правильные шаблоны для управления Singletons.

Вы можете видеть, что экземпляр класса Singleton, который имеет экземпляры (или не статические) члены, создается либо статической инициализацией, либо внутри статического конструктора.и присваивается переменной _singleton .. Мы используем этот шаблон, чтобы гарантировать, что он будет создан только один раз .Затем статический метод Instance предоставляет доступ только для чтения к переменной базового поля, которая содержит один и только один экземпляр Singleton.

public class Singleton {
   // static members
   private static readonly Singleton _singleton = new Singleton();
   public static Singleton Instance => _singleton

   // instance members
   private Singleton() { } // private so no one else can accidentally create an instance
   public string Gorp { get; set; }
}

или точно такую ​​же вещь, нос явным статическим конструктором:

public class Singleton {
   // static members
   private static readonly Singleton _singleton; // instead of here, you can...
   static Singleton() {
      _singleton = new Singleton(); // do it here
   }
   public static Singleton Instance => _singleton;

   // instance members
   private Singleton() { } // private so no one else can accidentally create an instance
   public string Gorp { get; set; }
}

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

public class Singleton {
   // static members
   public static Singleton Instance { get; } = new Singleton();

   // instance members
   private Singleton() { } // private so no one else can accidentally create an instance
   public string Gorp { get; set; }
}

Поскольку статические конструкторы гарантированно будут выполняться ровно один раз , будь то явные или неявные, то проблем с безопасностью потоков нет.Обратите внимание, что любой доступ к классу Singleton может вызвать статическую инициализацию, даже доступ типа отражения.

Вы можете думать о статических членах класса почти как об отдельных, хотя и соединенных, класс:

  1. Члены экземпляра (нестатические) функционируют как обычный класс.Они не живут, пока вы не выполните на них new Class().Каждый раз, когда вы делаете new, вы получаете новый экземпляр.Члены экземпляра имеют доступ ко всем статическим членам, включая закрытые (в одном классе).

  2. Статические члены похожи на элементы отдельного особого экземпляра класса, который вы не можете явно создатьиспользуя new.Внутри этого класса только статические члены могут быть доступны или установлены.Существует неявный или явный статический конструктор, который .Net запускается во время первого доступа (так же, как экземпляр класса, только вы не создаете его явно, он создается при необходимости).Статические члены класса могут быть доступны любому другому классу в любое время, в экземпляре или вне его, но с учетом модификаторов доступа, таких как internal или private.

3 голосов
/ 01 ноября 2011

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

Теперь вы можете использовать статическое поле в классе, и в этом случаеон существует до того, как будет создан (создан) класс.Могут быть случаи, когда вы захотите этого.

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

1 голос
/ 01 ноября 2011

Чтобы ответить на поставленный вопрос:

Невероятно (но возможно) создавать синглтон без статического поля.

Для этого вам нужно использовать чужое статическое поленапример AppDomain.GetData или (в ASP.Net) HttpContext.Application.

0 голосов
/ 01 ноября 2011

Просто чтобы ответить на ваш вопрос (я надеюсь): вместо того, чтобы использовать статический класс, содержащий статические члены, такие как Class1, вы можете реализовать шаблон Singleton, как в Class2 (пожалуйста, не начинайте обсуждение о отложенной инициализации на этом этапе):

public static class Class1
{
    public static void DoSomething ()
    {
    }
}

public static class Class2
{
    private Class2() {
    }

    private Class2 instance;

    public Class2 GetInstance(){
        if (instance == null)
            instance = new Class2();
        return instance;
    }

    public void DoSomething ()
    {
    }
}

Вместо вызова Class1.DoSomething() вы можете использовать Class2.GetInstance().DoSomething().

Редактировать: Как вы можете видеть, внутри Class2 все еще есть (приватное) статическое поле, содержащее его экземпляр.

Edit2 в ответ на комментарий пользователя 966638: Я правильно понимаю, что у вас есть такой код:

public class Foo {
    private static Bar bar;
}

А ваш коллега предлагает заменить его этим?

public class Foo {
    private BarSingleton bar;
}

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

0 голосов
/ 01 ноября 2011

И одноэлементные, и статические переменные дают вам один экземпляр класса.Почему вы предпочитаете singleton, а не static, это

  1. С Singleton вы можете сами управлять временем жизни экземпляра, так, как вам хочется
  2. С Singleton вы получаете больший контроль над инициализациейэкземпляр.Это полезно, когда инициализация экземпляра класса является сложным делом.
  3. Трудно сделать статические переменные поточно-ориентированными, с помощью singleton эта задача становится очень простой

Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...