Синглтон - PullRequest
       21

Синглтон

6 голосов
/ 02 ноября 2010

Этот вопрос, как и мой предыдущий вопрос, содержит ссылки Эффективная Java . На этот раз у меня немало подвопросов.

  1. Привилегированный клиент может рефлексивно вызывать приватный конструктор с помощью метода AccessibleObject.setAccessible(). Если вам нужно защититься от этого, измените конструктор.
    Как именно можно вызвать частный конструктор? А что такое AccessibleObject.setAccessible()?

  2. Какой подход вы, эксперты, используете с одиночками?

    // Approach A
    public class Test{
        public static final Test TestInstance = new Test();
        private Test(){ ... }
        .
        .
        .
    }
    
    
    // Approach B
    public class Test{
        private static final Test TestInstance = new Test();
        private Test(){ ... }
        public static Test getInstance() { return TestInstance; }
        .
        .
        .
    }
    

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

  3. Что если я попытаюсь клонировать класс / объект?

  4. Одноэлементный тип перечисления является лучшим способом реализации одиночного.
    Зачем? Как?

Ответы [ 5 ]

11 голосов
/ 02 ноября 2010

Привилегированный клинт может рефлексивно вызывать приватный конструктор с помощью метода AccessibleObject.setAccessible. Если вам нужно защитить это, измените конструктор.Мой вопрос: как именно может быть вызван частный конструктор?и что такое AccessibleObject.setAccessible ??

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

import java.lang.reflect.Constructor;

public class PrivateInvoker {
    public static void main(String[] args) throws Exception{
        //compile error 
//      Private p = new Private();

        //works fine
        Constructor<?> con = Private.class.getDeclaredConstructors()[0];
        con.setAccessible(true);
        Private p = (Private) con.newInstance();
    } 
}

class Private {
    private Private() {
        System.out.println("Hello!");
    } 
}

2. Какой подход вы, эксперты, используете с одиночками:

...

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

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

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

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

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

Что если я попытаюсь клонировать класс / объект?

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

тип перечисления с одним элементом - лучший способ реализации синглтона.Зачем?и как?

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

2 голосов
/ 02 ноября 2010

Синглтоны - хороший шаблон для изучения, особенно в качестве вводного шаблона дизайна. Остерегайтесь, однако, что они часто оказываются одним из наиболее излишне используемых шаблонов . Дошло до того, что некоторые считают их «анти-паттернами» . Лучший совет - "использовать их с умом".

Для хорошего ознакомления с этим и многими другими полезными шаблонами (лично я считаю, что Стратегия, Наблюдатель и Команда гораздо более полезны, чем Синглтон), ознакомьтесь с Head First Design Patterns .

2 голосов
/ 02 ноября 2010

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

Вы можете использовать отражение Java для вызова частных конструкторов.

Какой подход вы, эксперты, используете с одиночками:

Я фанат использования enum для этого. Это тоже в книге. Если это не вариант, сделать вариант a намного проще, потому что вам не нужно проверять или беспокоиться о том, что экземпляр уже создан.

Что если я попытаюсь клонировать класс / объект?

Не уверен, что вы имеете в виду? Вы имеете в виду clone () или что-то еще, чего я не знаю?

Одноэлементный тип перечисления - лучший способ реализации синглтона. Зачем? и как?

Ааа, мой собственный ответ. ха-ха. Это лучший способ, потому что в этом случае язык программирования Java гарантирует одиночный код вместо того, чтобы разработчик проверял наличие одиночного кода. Это как если бы синглтон был частью фреймворка / языка.

Edit: Я не видел, что это был добытчик раньше. Обновляя мой ответ на это - лучше использовать функцию, такую ​​как getInstance, потому что вы можете контролировать то, что происходит через геттер, но вы не можете сделать то же самое, если все вместо этого используют ссылку напрямую. Думай о будущем. Если вы в конечном итоге сделали SomeClass.INTANCE, а потом захотели сделать его ленивым, чтобы он не загружался сразу, вам нужно будет изменить это везде, где он используется.

1 голос
/ 02 ноября 2010

Первое правило шаблона Singleton (Anti-) - , не используйте его . Второе правило: , не используйте его с целью облегчения доступа к одному экземпляру класса, который вы хотите использовать совместно несколькими другими объектами, , особенно , если это зависимость этих классов. Вместо этого используйте внедрение зависимостей. Существуют допустимые варианты использования Singletons, но люди склонны злоупотреблять ими, потому что они так «просты» в использовании. Они очень затрудняют тестирование классов, которые зависят от них, и делают системы негибкими.

Что касается ваших вопросов, я думаю, что на 1 , 2 и 3 можно ответить, сказав "использовать enum -singleton". Тогда вам не нужно беспокоиться о проблемах доступности конструктора, clone() и т. Д. Что касается 4 , вышеприведенный аргумент является для них хорошим аргументом. Я также должен спросить, читали ли вы раздел «Эффективная Java», который явно отвечает на ваш вопрос?

0 голосов
/ 09 октября 2014

Пример синглтона ленивый init: класс main:

public class Main {

    public static void main(String[] args) {
        System.out.println(Singleton.getInstance("first").value);
        System.out.println(Singleton.getInstance("second").value);
        System.out.println(Singleton.getInstance("therd").value);
    }
}

Класс синглтона:

public class Singleton {
    private static Singleton instance;
    public String value;

    private Singleton (String s){
        this.value =s;
    }
    public static Singleton getInstance(String param) {
        if (instance == null) 
            instance = new Singleton(param);
        return instance;    
    }
}

При запуске приложения консоль будет содержать следующие строки:

first
first
first

\ | / 73

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