2016-11-01 3 views
0

Какое правильное использование синглтона, использующего статический синхронизированный метод getInstance и почему?Правильное использование метода Singleton getInstance

Например:

MySingleton mySingleton = MySingleton.getInstance(); 
..... 
mySingleton.doSomething(); 

mySingleton, где будет поле и используется по всему классу.

против

MySingleton.getInstance().doSomething(); 

EDIT: К собственно, я имею в виду стиль кодирования и безопасности потоков.

+1

В идеале вы не использовали бы Singleton вообще. Когда я должен, я предпочитаю использовать 'enum', в этом случае я бы написал' MySingleton.INSTANCE.doSomething() ' –

+1

Эти два примера идентичны, хотя @PeterLawrey имеет право рекомендовать перечисления для одиночных чисел. –

+0

Определите «правильное» - что конкретно вы спрашиваете? Это идентично, но в первом примере вы получаете экземпляр и используете его позже. –

ответ

1

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

а) стремится одноточечно

public class EagerSingleton{ 
    private EagerSingleton(){} 
    private static final EagerSingleton INSTANCE = new EagerSingleton(); 
    public static EagerSingleton getInstance(){ return INSTANCE; } 
} 

Это инициализируется во время класса нагрузки, всякий раз, когда вы ссылаетесь на класс EagerSingleton каким-либо образом (например, объявив переменную этого типа).

б) ленивым одноточечно

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

} 

Это инициализируется во время вызова, первый раз при вызове метода GetInstance(). Теперь загрузчик классов загружает класс держателя и инициализирует поле INSTANCE, и это гарантированно синхронизируется. Используйте эту версию, если ваш синглтон имеет дорогостоящую настройку и не всегда необходим.

с) перечисление Singleton

public enum EnumSingleton{ 
    INSTANCE; 

    // and if you want, you can add the method, too, but it's 
    // unnecessary: 
    public static EnumSingleton getInstance(){ return INSTANCE; } 
} 

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

версии перечисления дает много других возможностей бесплатно:

  • равна реализации/хэш-код/​​ToString из коробки
  • защиты от Десериализация атак
  • многотонной поддержки (просто добавьте еще один перечисление)

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

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

0

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

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

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

1

Лучшее решение, чем использование одноплодной является использование dependency injection:

class MyClass { 
    private final MySingleton mySingleton; 

    MyClass(MySingleton mySingleton) { 
    this.mySingleton = mySingleton; 
    } 

    // Use mySingleton in instance methods as required. 
} 

Преимущество здесь состоит в том, что тот факт, что это синглтон не имеет значения - это может быть синглтон, но это Безразлично» должно быть.

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

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

+0

Я согласен с тем, что мы не должны злоупотреблять Singletons. Теперь DI требует контейнер зависимостей, а singleton - нет. Если вы используете контейнер зависимостей или хотите его использовать, идея хорошая, но если вам это не нужно, и у вас есть 3 или 4 классических синглтона в вашем проекте, зачем добавлять эти накладные расходы? Тестирование синглтона сложнее, чем DI, но с отражением, оно очень воспроизводимо. – davidxxx

0

Кто-то должен создать экземпляр одноэлементного кода. Это нужно делать только один раз. Здесь идет поток safty в игру. Если есть шанс, что различные потоки называют

SingletonClass.getInstance(); 

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

private static volatile SingletonClass myInstance; 

public static SingletonClass getInstance() 
{ 
    if (myInstance == null) 
    { 
     synchronized(SingletonClass.class) 
     { 
      if (myInstance == null) 
      { 
       myInstance = new SingletonClass(); 
      } 
     } 
    } 

    return myInstance; 
} 

Это называется «проверил замок». Переменная должна быть изменчивой.

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

Ваш вопрос: в чем разница между «XY.getInstance(). DoSomething()» или «Сохранение ссылки в собственном члене для доступа к ней позже»: это лишь незначительное ограничение производительности (callstack еще один, if, return).Но IMO это невежественно, потому что в долгосрочной перспективе java-оптимизатор все равно включит это. С другой стороны: сохранение ссылки делает код короче и читабельнее, особенно если вы часто обращаетесь к синглтону. В конце это вопрос вкуса.

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