Когда следует использовать шаблон singleton вместо статического класса?

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

Ответ 1

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

Ответ 2

Как насчет "обойти оба"? Синглотоны и статические классы:

  • Может ввести глобальное состояние
  • Плотно подключаться к нескольким другим классам
  • Скрыть зависимости
  • Могут сделать классы тестирования модулей изолированно сложными

Вместо этого загляните в библиотеки Injection Dependency и Inversion of Control Container. Некоторые из библиотек IoC будут работать с вами для управления жизненным циклом.

(Как всегда, существуют исключения, такие как статические математические классы и методы расширения С#.)

Ответ 3

Я бы сказал, что единственное отличие - синтаксис: MySingleton.Current.Whatever() vs MySingleton.Whatever(). Государство, как сказал Давид, в конечном счете является "статическим".


РЕДАКТОР: Похожая бригада прибыла из digg... во всяком случае, я подумал о случае, которое потребует синглтона. Статические классы не могут наследовать от базового класса и не реализовывать интерфейс (по крайней мере, в .Net они не могут). Поэтому, если вам требуется эта функция, вы должны использовать синглтон.

Ответ 4

Одно из моих любимых обсуждений по этой проблеме - здесь (исходный сайт вниз, теперь связанный с Internet Way Way Machine.

Чтобы обобщить преимущества гибкости Singleton:

  • Синглтон может быть легко преобразован в factory
  • Синглтон может быть легко изменен, чтобы возвращать разные подклассы
  • это может привести к более удобному использованию

Ответ 5

Статический класс с нагрузкой статических переменных немного взломан.

/**
 * Grotty static semaphore
 **/
 public static class Ugly {

   private static int count;

   public synchronized static void increment(){
        count++;
   }

   public synchronized static void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized static boolean isClear(){
         return count==0;    

    }
   }

Синтаксис с фактическим экземпляром лучше.

/**
 * Grotty static semaphore
 **/
 public static class LessUgly {
   private static LessUgly instance;

   private int count;

   private LessUgly(){
   }

   public static synchronized getInstance(){
     if( instance==null){
        instance = new LessUgly();
     }
     return instance;
   }
   public synchronized void increment(){
        count++;
   }

   public synchronized void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized boolean isClear(){
         return count==0;    

    }
   }

Состояние находится в ТОЛЬКО в экземпляре.

Таким образом, singleton может быть изменен позже, чтобы сделать пул, потоковые локальные экземпляры и т.д. И ни один из уже написанного кода не нуждается в изменении, чтобы получить выгоду.

public static class LessUgly {
       private static Hashtable<String,LessUgly> session;
       private static FIFO<LessUgly> freePool = new FIFO<LessUgly>();
       private static final POOL_SIZE=5;
       private int count;

       private LessUgly(){
       }

       public static synchronized getInstance(){
         if( session==null){
            session = new Hashtable<String,LessUgly>(POOL_SIZE);
            for( int i=0; i < POOL_SIZE; i++){
               LessUgly instance = new LessUgly();  
               freePool.add( instance)
            }
         }
         LessUgly instance = session.get( Session.getSessionID());
         if( instance == null){
            instance = freePool.read();
         }
         if( instance==null){
             // TODO search sessions for expired ones. Return spares to the freePool. 
             //FIXME took too long to write example in blog editor.
         }
         return instance;
       }     

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

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

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

Ответ 6

Подумайте о синглете как услуге. Это объект, который предоставляет определенный набор функций. Например.

ObjectFactory.getInstance().makeObject();

Объект factory - это объект, который выполняет определенную службу.

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

StringUtils.reverseString("Hello");
StringUtils.concat("Hello", "World");

В примере StringUtils представлен набор функций, которые можно применять в любом месте. Объект singleton factory - это конкретный тип объекта с четкой ответственностью, которая может быть создана и передана там, где это необходимо.

Ответ 7

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

Ответ 8

Синглтоны не должны использоваться так же, как статические классы. В сущности,

MyStaticClass.GetInstance().DoSomething();

по существу совпадает с

MyStaticClass.DoSomething();

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

var svc = new MyComplexServce(MyStaticClass.GetInstance());

Служба не должна знать, что объект является одиночным, и должен рассматривать объект как просто объект.

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

Ответ 9

Если под "статическим классом" вы подразумеваете класс, который имеет только статические переменные, то они фактически могут поддерживать состояние. Я понимаю, что единственное различие заключается в том, как вы получаете доступ к этой вещи. Например:

MySingleton().getInstance().doSomething();

против

MySingleton.doSomething();

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

Ответ 10

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

Ответ 11

Синглтоны никогда не должны использоваться (если вы не рассматриваете класс без изменяемого состояния singleton). "статические классы" не должны иметь изменяемого состояния, кроме, возможно, потокобезопасных кешей и т.п.

Практически любой пример синглтона показывает, как это не делать.

Ответ 12

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

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

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

Ответ 13

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

Итак, если вы пишете новый класс, который вы планируете разрешить только одному экземпляру кода, вы можете написать его как Singleton. Подумайте об этом, написав класс простой jane и добавляя к нему, чтобы облегчить требование о создании экземпляра. Если вы используете другой класс, который нельзя изменить (например, mysqli), вы должны использовать статический класс (даже если вы не префикс его определения с ключевым словом).

Ответ 14

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

Ответ 15

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

гр

Ответ 16

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

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

Foo foo = Foo.getInstance();
doSomeWork(foo); // doSomeWork wont even know Foo is a singleton

Это, очевидно, упрощает работу, когда вы выбираете шаблон Singleton в пользу реального шаблона, такого как IoC.

Ответ 17

Используйте шаблон singleton, когда вам нужно вычислить что-то во время выполнения, которое вы могли бы вычислить во время компиляции, если бы вы могли, например таблицы поиска.

Ответ 18

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

Ответ 19

Синтаксис также является хорошей идеей, если вы хотите добиться эффективного кэширования данных. например, у меня есть класс, который ищет определения в XML-документе. Поскольку разбор документа может занять некоторое время, я настроил кеш определений (я использую SoftReferences, чтобы избежать outOfmemeoryErrors). Если желаемого определения нет в кеше, я делаю дорогостоящий синтаксический анализ xml. В противном случае я возвращаю копию из кеша. Поскольку наличие нескольких кэшей будет означать, что мне все равно придется загружать одно и то же определение несколько раз, мне нужно иметь статический кеш. Я решил реализовать этот класс как singleton, чтобы я мог писать класс, используя только обычные (нестатические) элементы данных. Это позволяет мне по-прежнему создавать istantiation класса, если мне это нужно по какой-либо причине (сериализация, модульное тестирование и т.д.).

Ответ 20

Синглтон - это как сервис, как уже упоминалось. Pro - это его гибкость. Статический, ну, для внедрения Singleton вам нужны некоторые статические части.

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

Однако, как и Singleton, можно построить некоторые статические переменные, вы можете сравнить его с 'goto'. Это может быть полезно для создания других структур, но вам действительно нужно знать, как его использовать, и не следует "злоупотреблять" им. Поэтому общая рекомендация - придерживаться Синглтона и использовать статику, если вам нужно.

также проверьте другое сообщение: Зачем выбирать статический класс по сравнению с одноэлементной реализацией?

Ответ 21

отсылайте this

Резюме:

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

б. используйте Singleton, если это особенно "тяжелый" объект. Если ваш объект большой и занимает разумный объем памяти, много н/д звонков (пул подключений)..etc. Чтобы убедиться, что он не будет создан несколько раз. Класс Singleton поможет предотвратить такой случай, когда-либо происходящее

Ответ 22

Если для одного класса требуется состояние. Синглтоны поддерживают глобальное состояние, статические классы этого не делают.

Например, создание помощника вокруг класса реестра: если у вас есть изменяемый куст (HKey Current User или HKEY Local Machine), вы можете пойти:

RegistryEditor editor = RegistryEditor.GetInstance();
editor.Hive = LocalMachine

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