Шаблон проектирования Java Singleton: Вопросы - PullRequest
17 голосов
/ 07 августа 2010

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

Кажется, он наполовину удовлетворен ответом, но я хочу знать

  1. Сколько разных способов мы можем реализовать шаблон проектирования Singleton в Java?
  2. Каков охват Singleton Object и как он на самом деле работает внутри JVM? Я знаю, что у нас всегда будет один экземпляр Singleton Object, но какова фактическая область действия этого объекта, является ли она в JVM или если запущено несколько приложений, чем область действия для каждого контекста внутри JVM, я был действительно озадачен этим и не смог дать удовлетворительного объяснения?
  3. Наконец, он спросил, возможно ли использовать Singleton Object с Clusters с объяснением, и есть ли способ заставить Spring не реализовывать Singleton Design Pattern, когда мы вызываем Bean Factory для получения объектов?

Любые отзывы будут высоко оценены в отношении синглтона, и что нужно учитывать при работе с синглетонами?

Спасибо.

Ответы [ 11 ]

15 голосов
/ 07 августа 2010

Существует несколько способов реализации шаблона Singleton в Java:

// private constructor, public static instance
// usage: Blah.INSTANCE.someMethod();
public class Blah {
    public static final Blah INSTANCE = new Blah();
    private Blah() {
    }
    // public methods
}

// private constructor, public instance method
// usage: Woo.getInstance().someMethod();
public class Woo {
    private static final Woo INSTANCE = new Woo();
    private Woo() {
    }
    public static Woo getInstance() {
        return INSTANCE;
    }
    // public methods
}

// Java5+ single element enumeration (preferred approach)
// usage: Zing.INSTANCE.someMethod();
public enum Zing {
    INSTANCE;
    // public methods
}

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

Наконец, определение не-одиночного объекта весной выполняется просто через атрибут singleton = "false".

2 голосов
/ 07 августа 2010

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

public enum Singleton { ONE_AND_ONLY_ONE ; ... members and other junk ... }

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

2 голосов
/ 07 августа 2010

Я не согласен с @ неопровержимым.

Область действия Singleton - это его узел в дереве Classloader. Он содержит загрузчик классов, и любой дочерний загрузчик классов может видеть синглтон.

Важно понимать эту концепцию области действия, особенно на серверах приложений, которые имеют сложную иерархию Classloader.

Например, если у вас есть библиотека в jar-файле на системном пути к классу сервера приложений, и эта библиотека использует Singleton, этот Singleton будет (вероятно) одинаковым для каждого «приложения», развернутого в сервер приложений. Это может или не может быть хорошей вещью (зависит от библиотеки).

Загрузчики классов, IMHO, являются одним из наиболее важных понятий в Java и JVM, и Singletons играют в этом прямую роль, поэтому я думаю, что для программиста на Java важно «заботиться».

1 голос
/ 07 августа 2010

3: В заключение он спросил, возможно ли использовать объект Singleton с кластерами с пояснениями, и есть ли способ заставить Spring не реализовывать шаблон проектирования Singleton, когда мы вызываем Bean Factory для получения объектов?

На первую часть этого вопроса трудно ответить без технологического контекста.Если платформа кластера включает в себя возможность совершать вызовы удаленных объектов, как если бы они были локальными объектами (например, как это возможно с EJB, использующими RMI или IIOP под капотом), тогда да, это можно сделать.Например, резидентные одноэлементные объекты JVM могут быть прокси для одноэлементного объекта всего кластера, который изначально был расположен / подключен через JNDI или что-то в этом роде.Но синглеты всего кластера являются потенциальным узким местом, потому что каждый вызов одного из одноэлементных прокси приводит к (дорогостоящему) RPC для одного удаленного объекта.

Вторая часть вопроса заключается в том, что Spring Bean Factories могут бытьнастроен с разными областями применения.По умолчанию для синглетов (область действия на уровне веб-приложения), но они также могут быть областью сеанса или запроса, или приложение может определить свой собственный механизм определения области действия.

1 голос
/ 07 августа 2010

Синглтон обычно реализуется с помощью статического экземпляра объекта (private SingletonType SingletonType.instance), который лениво создается с помощью статического SingletonType SingletonType.getInstance() метода.Существует много ловушек при использовании синглетонов, так много, что многие считают синглтон анти-шаблонным дизайном.Учитывая вопросы о Spring, интервьюер, вероятно, искал понимание не только синглетонов, но и их ловушек, а также обходного пути для этих ловушек, известных как внедрение зависимостей.Вы можете найти видео на странице Google Guice особенно полезным для понимания ловушек синглетонов и того, как DI решает эту проблему.

0 голосов
/ 05 февраля 2017

Singleton - это шаблон творческого проектирования.

Содержание шаблона проектирования Singleton:

  • Убедитесь, что у класса есть только один экземпляр, и укажите глобальную точку доступ к нему.
  • Инкапсулированная «своевременная инициализация» или «инициализация при Первое использование ".

Здесь я показываю три типа реализации.

  1. Как раз во время инициализации (выделяет память во время первого запуска, даже если вы ее не используете)

    class Foo{
    
        // Initialized in first run
        private static Foo INSTANCE = new Foo();
    
        /**
        * Private constructor prevents instantiation from outside
        */
        private Foo() {}
    
        public static Foo getInstance(){
            return INSTANCE;
        }
    
    }
    
  2. Инициализация при первом использовании (или Ленивая инициализация)

    class Bar{
    
        private static Bar instance;
    
        /**
        * Private constructor prevents instantiation from outside
        */
        private Bar() {}
    
        public static Bar getInstance(){
    
            if (instance == null){
                // initialized in first call of getInstance()
                instance = new Bar();
            }
    
            return instance;
        }
    }
    
  3. Это еще один стиль инициализации Lazy, но преимущество в том, что это решение поточно-ориентированное, не требующее специальных языковых конструкций (то есть volatile или синхронизированные). Узнайте больше на SourceMaking.com

    class Blaa{
    
        /**
         * Private constructor prevents instantiation from outside
         */
        private Blaa() {}
    
        /**
         * BlaaHolder is loaded on the first execution of Blaa.getInstance()
         * or the first access to SingletonHolder.INSTANCE, not before.
         */
        private static class BlaaHolder{
            public static Blaa INSTANCE = new Blaa();
        }
    
        public static Blaa getInstance(){
            return BlaaHolder.INSTANCE;
        }
    
    }
    
0 голосов
/ 19 марта 2016

Запрос 1:

Различные способы создания синглтона

  1. Normal Singleton: статическая инициализация
  2. ENUM
  3. Lazy Singleton: двойная блокировка синглтона &: инициализация по требованию_держателя_idiom синглтона

Посмотрите на приведенный ниже код:

public final class Singleton{
    private static final Singleton instance = new Singleton();

    public static Singleton getInstance(){
        return instance; 
    }
    public enum EnumSingleton {
        INSTANCE;   
    }   
    public static void main(String args[]){
        System.out.println("Singleton:"+Singleton.getInstance());
        System.out.println("Enum.."+EnumSingleton.INSTANCE);
        System.out.println("Lazy.."+LazySingleton.getInstance());
    }
}
final class LazySingleton {
    private LazySingleton() {}
    public static LazySingleton getInstance() {
        return LazyHolder.INSTANCE;
    }
    private static class LazyHolder {
        private static final LazySingleton INSTANCE = new LazySingleton();
    }
}

Связанные вопросы SE:

Как эффективен способ реализации одноэлементного шаблона в Java?

Запрос 2:

Один экземпляр Singleton создается для ClassLoader. Если вы хотите избежать создания Singleton объекта во время Serializaiton, переопределите метод ниже и верните тот же экземпляр.

private Object readResolve()  { 
    return instance; 
}

Запрос 3:

Для достижения уровня кластера Singleton среди нескольких серверов сохраните этот объект Singleton в распределенных кешах, таких как Terracotta, Coherence и т. Д.

0 голосов
/ 07 августа 2010

Следующий код взят из здесь

Ключевым моментом является то, что вы должны Override метод clone ... Пример Wikipedia также полезен.

public class SingletonObject
{
  private SingletonObject()
  {
    // no code req'd
  }

  public static SingletonObject getSingletonObject()
  {
    if (ref == null)
        // it's ok, we can call this constructor
        ref = new SingletonObject();        
    return ref;
  }

  public Object clone()
    throws CloneNotSupportedException
  {
    throw new CloneNotSupportedException(); 
    // that'll teach 'em
  }

  private static SingletonObject ref;
}
0 голосов
/ 07 августа 2010

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

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

Как указывалось другими авторами, загрузчик классов в java будет определять область действия синглтона. Синглтоны в кластерах обычно являются «не единичными экземплярами», а набором экземпляров, которые демонстрируют похожее поведение. Это могут быть компоненты в SOA.

0 голосов
/ 07 августа 2010
  1. Есть стандартный способ, который вы уже рассмотрели. Кроме того, большинство схем внедрения зависимостей имеют некоторый способ пометить класс как одиночный; таким образом, класс выглядит так же, как и любой другой, но среда гарантирует, что когда вы внедряете экземпляры этого класса, это всегда один и тот же экземпляр.

  2. Вот где это становится волосатым. Например, если класс инициализируется в контексте приложения Tomcat, то время жизни экземпляра одиночного экземпляра привязывается к этому контексту. Но может быть трудно предсказать, где ваши классы будут инициализированы; так что лучше не делать никаких предположений. Если вы хотите абсолютно точно убедиться, что для каждого контекста существует только один экземпляр, вы должны связать его как атрибут ServletContext. (Или пусть структура внедрения зависимостей позаботится об этом.)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...