2010-08-20 2 views
32

Каким образом одноэлемент отличается от класса, заполненного только статическими полями?В чем разница между шаблоном Singleton и статическим классом в Java?

+1

Вы спрашиваете: «Каковы практические различия?» –

+0

Мне просто интересно узнать об общих отличиях двух, т. Е. Существует ли что-то уникальное в отношении Singleton, которое отличает его от класса, у которого есть все его методы и атрибуты, установленные в static? – cesar

+0

DCL способ реализации singleton имеет только экземпляр статического поля, содержащий статическую ссылку на одноэлементный объект, а затем лениво созданный в статическом методе. В этом случае эта реализация Singleton имеет только статическое поле и методы, и они одинаковы (не отличается, как задает вопрос). Это одна реализация. Другое может быть через Enum. – nanosoft

ответ

32

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

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

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

Одноэлементный шаблон всего в нескольких шагах от статических классов. Вы получаете сорта, но если вы обращаетесь к ним непосредственно внутри других классов с помощью класса ClassName.Instance, вы создаете препятствие для доступа к этим преимуществам. Как указано в ph0enix, вам гораздо лучше использовать шаблон инъекции зависимостей. Таким образом, инфраструктуре DI можно сказать, что конкретный класс является (или нет) синглом. Вы получаете все преимущества от насмешек, модульного тестирования, полиморфизма и большей гибкости.

+0

В java вложенный статический класс может расширить другой класс (а также может быть расширен другими классами) и реализовать интерфейсы. проверьте http://stackoverflow.com/a/37114702/1406510 – nanosoft

+3

@nanosoft: Когда я сказал «статический класс», я не имел в виду Java [«статические вложенные классы»] (http://docs.oracle. com/javase/tutorial/java/javaOO/nested.html), а скорее «класс, заполненный только статическими полями», о чем спрашивал OP. Все утверждения, которые я делаю здесь, применяются, если вы думаете с точки зрения использования статических методов, независимо от характера класса, в котором они находятся: они не могут реализовать интерфейсы или быть расширенными.Извините за любую путаницу, которую я, возможно, вызвал, сказав «статический класс» - это термин, который более распространен на других языках, но не применяется в Java. – StriplingWarrior

2

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

+0

На самом деле, я думаю, что наличие синглтона помогает сократить количество глобальных переменных. У вас есть одна ссылка на объект. Он может обернуть в него все статические поля. – BenoitParis

+4

@BenoitParis - он уменьшает абсолютное число глобальных переменных, но не решает ни одного связанного с ними зла. –

+2

В первую очередь вы не должны иметь глобальных переменных. Даже статические методы не являются ООП. –

5

Одиночный синглтон можно инициализировать лениво, для одного.

+2

Статика в любом случае. –

+0

@Tom Hawtin - tackline: что вы подразумеваете под этим? – JRL

+6

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

2

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

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

+0

Вопрос спрашивает о полях, а не методах. –

+0

Небольшой пул одиночных объектов? Я предполагаю, что это имеет смысл, для некоторой ценности «маленького». –

3

Разница не зависит от языка. Singleton по определению: «Убедитесь, что класс имеет только один экземпляр и предоставляет глобальную точку доступа к нему». Класс, заполненный только статическими полями, не такой же, как singleton, но, возможно, в вашем сценарии использования они обеспечивают ту же функциональность. Но, как сказал JRL, ленивое посвящение - это одно отличие.

2

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

В то время как класс с только статическими методами, нет необходимости создавать экземпляр (по этой причине большинство людей/фреймворков делают подобные классы Util абстрактными). Вы просто вызовете методы на классе напрямую.

1

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

class NoSingleton { 
    static { 
    //initialize foo with something complex that can't be done otherwise 
    } 
    static private foo; 
} 

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

+0

Я думаю, что вы говорите, что синглтоны - это «не очень хорошая идея», когда мы ничего не знаем о контексте, который он может использовать, это немного сыпь. В программировании нет абсолютов, и почти всегда используется прецедент, который делает тот или другой лучшим. Это как сказать кому-то слово «утка» всегда относится к животному. Но контекст важен, поскольку это может означать нечто совершенно иное, как «Утка, когда кто-то бросает вам шоу». Постскриптум Но я не спустил тебя вниз. – AaronLS

0

ПРИМЕЧАНИЕ. Примеры приведены на C#, так как это то, с чем я более знаком, но концепция должна применяться к Java одинаково.

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

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

Плохо дизайн с использованием статического класса:

public class MyClass 
{ 
    public void SomeMethod(string filename) 
    { 
     if (File.Exists(filename)) 
     // do something 
    } 
} 

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

public class MyClass 
{ 
    private IFileSystem m_fileSystem; 

    public MyClass(IFileSystem fileSystem) 
    { 
     m_fileSystem = fileSystem; 
    } 

    public void SomeMethod(string filename) 
    { 
     if (m_fileSystem.FileExists(filename)) 
     // do something 
    } 
} 

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

0

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

+0

Вложенный статический класс также может расширять другой класс и реализовывать интерфейс. http://stackoverflow.com/a/37114702/1406510 – nanosoft

0

Singleton Класс: Singleton Класс - класс, из которого может существовать только один экземпляр для каждого загрузчика классов.

Класс помощника (класс с только статическими полями/методами): Нет экземпляра этого класса. Только поля и методы могут быть напрямую доступны как константы или вспомогательные методы.

Эти несколько строк из этого blog описывает это красиво:

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

11

Давайте мне подытожить :)

Существенное отличие заключается в следующем: существование форма одноточечного является объектом, статический не является. Это привело к следующим вещам:

  • Singleton может быть расширен. Статический нет.
  • Создание Singleton может быть неточным, если оно не выполнено должным образом. Статический нет.
  • Singleton можно передавать как объект. Статический нет.
  • Singleton может быть собранным мусором. Статический нет.
  • Singleton лучше, чем статический класс!
  • Больше здесь, но я не понял еще :)

И последнее, но не в последнюю очередь, когда вы собираетесь реализовать синглтон, пожалуйста, рассмотреть перепроектировать свою идею не использовать этот объект Бога (поверьте, вы склонны вкладывать все «интересные» вещи в этот класс) и вместо этого использовать обычный класс с именем «Контекст» или что-то подобное.

+0

+1 для принципа «Бог-объект». Любить это. – StriplingWarrior

+0

В java вложенный статический класс может расширять другой класс (а также может быть расширен другими классами). статический вложенный класс может быть очень передан как объект. Это может быть сбор мусора. check http://stackoverflow.com/a/37114702/1406510 – nanosoft

+0

Статические классы могут быть потокобезопасными или не потокобезопасными. – user2864740

3

Я думаю, что значительная вещь - это «объект» в объектно-ориентированном программировании. За исключением нескольких случаев, мы должны ограничивать использование статических классов. Это случаи:

  1. Когда создание объекта бессмысленно. Как и методы java.lang.Math. Мы можем использовать класс как объект. Поскольку поведение методов класса Math не зависит от состояния объектов, которые должны быть созданы в этом классе.
  2. коды, которые будут использоваться совместно более чем одного метода объекта, коды, которые не достигают переменных объекта и, вероятно, будут закрыты могут быть статические методы

Другая важная вещь синглтон является расширяемым. Singleton может быть расширен. В классе Math, используя конечные методы, было предотвращено создание и расширение объекта этого класса. То же самое верно для класса java.lang.System. Однако класс Runtime - это единственный объект, а не статический метод. В этом случае вы можете переопределить методы наследования класса Runtime для разных целей.

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

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

+0

# 1 следует принимать в контексте. Возьмите «бессмысленный» вызов «Date.Now». но 99,99% времени, используя статический вызов метода «Date.Now», делает насмешливые тесты практически невозможными. Вернее, статические методы * не позволяют вообще впрыскивать и насмехаться. – user2864740

Смежные вопросы