2014-02-06 2 views
10

я получил две версии «Initialization по требованию владельца идиомы»:Правильное выполнение инициализации по требованию владельца идиомы

  1. http://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom
  2. http://en.wikipedia.org/wiki/Singleton_pattern#The_solution_of_Bill_Pugh

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

Скажите, пожалуйста, какой из них следует использовать.


К сожалению, я не нашел разницы между использованием частного и общественности в моем приложении:

public class Singleton { 
    private int x; 
    public int getX() { 
     return x; 
    } 

    private Singleton() {} 

    private static class LazyHolder { 
     //both private and public works 
     private static final Singleton INSTANCE = new Singleton(); 
    } 

    public static Singleton getInstance() { 
     return LazyHolder.INSTANCE; 
    } 
} 

Единственное, что я делаю, чтобы назвать что-то вроде Singleton.getInsance().getX(), так что обе версии работает. Таким образом, я хочу знать ситуации для их использования.

ответ

10

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

1) Модификатор доступа:

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

public class Singleton { 
    ... 
    private static class LazyHolder { 
     static final Singleton INSTANCE = new Singleton(); 
    } 
    public static Singleton getInstance() { 
     return LazyHolder.INSTANCE; 
    } 
} 

Однако JLS 6.6.1 объясняет:

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

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

На самом деле, это не имеет значения, какой модификатор вы на нем размещаете. Если он является общедоступным, он по-прежнему не может быть доступен из других классов, кроме Singleton. Однако ... Я думаю, что доступ к пакету является лучшим. Публикация не имеет смысла. Заставляя его частным образом заставить компилятор делать некоторые трюки. Составление частного пакета отражает то, что у вас есть: доступ к члену класса из другого класса.

2) Как реализовать синглтон:

Если вы когда-либо рассмотреть вопрос о сериализации, реализация синглтон будет получить немного сложнее. Джошу Блох написал большой раздел в своей книге «Эффективная Ява» о внедрении синглонов. В конце концов, он пришел к выводу, что для этого просто используется перечисление, поскольку спецификация enum Java предоставляет все харектеристики, которые необходимы в отношении одиночных чисел. Конечно, это больше не использует идиому.

3) Принимая во внимание дизайн:

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

+0

Объявление поля как ** частного ** позволит компилятору вставить ** пакет частных ** методов, правильно? –

+0

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

+0

@Seelenvirtuose, какие проблемы могут возникнуть, если LazyHolder не делает INSTANCE окончательным – masT

3
private static class LazyHolder { 
    $VISIBILITY static final Singleton INSTANCE = new Singleton(); 

С точки зрения потребителя зрения это не имеет значения, если $ VISIBILITY является публичным или частным порядком, так как LazyHolder типа является частным. Переменная доступна только через статический метод в обоих случаях.

+1

Я всегда не использую ни один из них - я использую видимость по умолчанию (т.е. опускаю), потому что это одно слово для ввода и чтения кода. – Bohemian

2

Я использую номер 1 (частная ИНСТАНЦИЯ), потому что вы, как правило, стараетесь максимально использовать самый узкий объём. Но в этом случае, поскольку класс Гёльдера является частным, это не имеет большого значения. Однако предположим, что кто-то позже решил сделать класс Holder общедоступным, а номер 2 может быть проблематичным с точки зрения инкапсуляции (вызывающие могут обойти метод getInstance() и напрямую обращаться к статическому полю).

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