Когда следует использовать шаблон Singleton вместо статического класса?[закрыто]

StackOverflow https://stackoverflow.com/questions/46541

  •  09-06-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

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

Другие советы

Как насчет «избегать обоих»?Синглтоны и статические классы:

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

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

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

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


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

Одно из моих любимых обсуждений на эту тему: здесь (исходный сайт закрыт, теперь ссылка на Интернет-архив Wayback Machine.)

Подводя итог преимуществам гибкости Singleton:

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

Статический класс с множеством статических переменных — это своего рода хак.

/**
 * 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;    

    }
   }

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

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

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;
       }     

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

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

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

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

ObjectFactory.getInstance().makeObject();

Фабрика объектов — это объект, выполняющий определенную услугу.

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

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

Пример StringUtils представляет собой набор функций, которые можно применять где угодно.Фабричный объект Singleton — это объект особого типа с четкой ответственностью, который можно создавать и передавать там, где это необходимо.

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

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

MyStaticClass.GetInstance().DoSomething();

по сути то же самое, что

MyStaticClass.DoSomething();

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

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

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

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

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

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

против

MySingleton.doSomething();

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

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

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

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

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

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

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

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

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

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

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

рп

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

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

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

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

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

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

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

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

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

Однако так же, как Singleton может быть создан с некоторыми статическими переменными, вы можете сравнить его с «goto».Он может быть очень полезен для создания других структур, но вам действительно нужно знать, как его использовать, и не следует «злоупотреблять» им.Поэтому общая рекомендация — придерживаться Singleton и при необходимости использовать static.

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

ссылаться этот

краткое содержание:

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top