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


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

22 84

22 ответа:

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

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

  • может ввести глобальное состояние
  • вам тесно связаны с несколькими другими классами
  • скрыть зависимостей
  • может сделать классы модульного тестирования в изоляции трудно

вместо этого, посмотрите в Инъекции Зависимостей и инверсия контейнера управления библиотеки. Несколько библиотек МОК будут обрабатывать управление временем жизни для вы.

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

Я бы сказал, что единственное различие-это синтаксис: MySingleton.Текущий.Whatever () vs MySingleton.Все.)( Государство, как упоминал Дэвид, в конечном счете "статично" в любом случае.


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

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

чтобы суммировать преимущества гибкости Синглтона:

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

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

/**
 * 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 здесь представляет собой набор функциональных возможностей, которые могут быть применены в любом месте. Этот одноэлементный заводской объект-это определенный тип объекта с четкой ответственностью, который может быть создан и передан по мере необходимости.

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

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

MyStaticClass.GetInstance().DoSomething();

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

MyStaticClass.DoSomething();

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

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

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

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

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

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

и

MySingleton.doSomething();

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

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

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

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

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

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

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

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

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

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

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

rp

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

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

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

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

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

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

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

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

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

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

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

см. этой

резюме:

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

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

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

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

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

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