Синглтон с аргументами в Java

«Это» - все о сфере видимости. Каждая функция имеет свою собственную область действия, и поскольку все в JS является объектом, даже функция может хранить некоторые значения в себе, используя «это». ООП 101 учит, что «это» применимо только к экземплярам объекта. Поэтому каждый раз, когда выполняет функция, новый «экземпляр» этой функции имеет новое значение «this».

Большинство людей путаются, когда пытаются использовать «это» внутри анонимных функций закрытия например:

(function(value) {
    this.value = value;
    $('.some-elements').each(function(elt){
        elt.innerHTML = this.value;        // uh oh!! possibly undefined
    });
})(2);

Итак, внутри each (), «this» не содержит «значение», которое вы ожидаете от него (от

this.value = value;
над ним). Итак, чтобы справиться с этой проблемой (без каламбуры), разработчик мог:

(function(value) {
    var self = this;            // small change
    self.value = value;
    $('.some-elements').each(function(elt){
        elt.innerHTML = self.value;        // phew!! == 2 
    });
})(2);

попробовать; вам понравится эта схема программирования

130
задан 26 June 2009 в 20:55
поделиться

8 ответов

Я очень четко изложу свою точку зрения: синглтон с параметрами не является singleton .

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

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

SingletonObj singleton = SingletonObj.getInstance();
singleton.init(paramA, paramB); // init the object with data

Если операция, которую выполняет ваш синглтон, является повторяющейся и каждый раз с разными параметрами, с таким же успехом вы можете передать параметры выполняемому основному методу:

SingletonObj singleton = SingletonObj.getInstance();
singleton.doSomething(paramA, paramB); // pass parameters on execution

В любом случае создание экземпляра всегда будет без параметров.

161
ответ дан 24 November 2019 в 00:24
поделиться

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

Одноэлементный объект с аргументом в любом случае не имеет смысла - что бы произошло, если бы вы написали:

Singleton s = SingletonHolder.getInstance(1);
Singleton t = SingletonHolder.getInstance(2); //should probably throw IllegalStateException

Ваш одноэлементный объект также не является потокобезопасным , поскольку несколько потоков могут выполнять одновременные вызовы getInstance , в результате чего создается более одного экземпляра (возможно, с разными значениями x ).

-5
ответ дан 24 November 2019 в 00:24
поделиться

Синглтон, конечно, является «анти-шаблоном» (при условии определения статики с переменным состоянием).

Если вам нужен фиксированный набор объектов неизменяемых значений, тогда перечисления путь к успеху. Для большого, возможно, открытого набора значений вы можете использовать репозиторий в той или иной форме - обычно на основе реализации Map . Конечно, когда вы имеете дело со статикой, будьте осторожны с потоками (либо синхронизируйте достаточно широко, либо используйте ConcurrentMap , либо проверяя, что другой поток не побил вас, либо используйте некоторую форму фьючерсов).

-2
ответ дан 24 November 2019 в 00:24
поделиться

Причина, по которой вы не можете понять, как выполнить то, что вы пытаетесь сделать, вероятно, состоит в том, что то, что вы пытаетесь сделать, на самом деле не имеет смысла. Вы хотите вызвать getInstance (x) с разными аргументами, но всегда возвращать один и тот же объект? Какое поведение вы хотите, когда вы вызываете getInstance (2) , а затем getInstance (5) ?

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

3
ответ дан 24 November 2019 в 00:24
поделиться

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

Singleton.getInstance().setX(value);
6
ответ дан 24 November 2019 в 00:24
поделиться

Я думаю, вам понадобится что-то вроде factory , чтобы создавать и повторно использовать объекты с различными параметрами. Это может быть реализовано с помощью синхронизированного HashMap или ConcurrentHashMap , отображающего параметр (например, Integer ) в параметризуемый класс «singleton».

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

Вот пример такого хранилища:

public final class UsefulObjFactory {

    private static Map<Integer, UsefulObj> store =
        new HashMap<Integer, UsefulObj>();

    public static final class UsefulObj {
        private UsefulObj(int parameter) {
            // init
        }
        public void someUsefulMethod() {
            // some useful operation
        }
    }

    public static UsefulObj get(int parameter) {
        synchronized (store) {
            UsefulObj result = store.get(parameter);
            if (result == null) {
                result = new UsefulObj(parameter);
                store.put(parameter, result);
            }
            return result;
        }
    }
}

Чтобы продвинуть его еще дальше , Java enum может также рассматриваться (или использоваться как) параметризованные синглтоны, хотя допускает только статические варианты с фиксированным числом.

Однако, если вам нужно распределенное решение 1 , рассмотрите какое-нибудь решение для бокового кеширования.

39
ответ дан 24 November 2019 в 00:24
поделиться

В вашем примере вы не используете синглтон. Обратите внимание, что если вы сделаете следующее (при условии, что Singleton.getInstance был на самом деле статическим):

Singleton obj1 = Singleton.getInstance(3);
Singleton obj2 = Singleton.getInstance(4);

Тогда значение obj2.x равно 3, а не 4. Если вам нужно сделать это, сделайте его простым классом. Если количество значений небольшое и фиксированное, вы можете рассмотреть возможность использования перечисления enum . Если у вас возникла проблема с чрезмерной генерацией объектов (что обычно не так), вы можете рассмотреть возможность кеширования значений (и проверить источники или получить помощь с этим, поскольку очевидно, как создавать кеши без опасности утечки памяти).

Вы также можете прочитать эту статью , так как синглтоны очень легко злоупотреблять.

3
ответ дан 24 November 2019 в 00:24
поделиться

Модификация шаблона Singleton, использующая идиому Билла Пью об инициализации по запросу. Это потокобезопасно без накладных расходов на специализированные языковые конструкции (т.е. изменчивые или синхронизированные):

public final class RInterfaceHL {

    /**
     * Private constructor prevents instantiation from other classes.
     */
    private RInterfaceHL() { }

    /**
     * R REPL (read-evaluate-parse loop) handler.
     */
    private static RMainLoopCallbacks rloopHandler = null;

    /**
     * SingletonHolder is loaded, and the static initializer executed, 
     * on the first execution of Singleton.getInstance() or the first 
     * access to SingletonHolder.INSTANCE, not before.
     */
    private static final class SingletonHolder {

        /**
         * Singleton instance, with static initializer.
         */
        private static final RInterfaceHL INSTANCE = initRInterfaceHL();

        /**
         * Initialize RInterfaceHL singleton instance using rLoopHandler from
         * outer class.
         * 
         * @return RInterfaceHL instance
         */
        private static RInterfaceHL initRInterfaceHL() {
            try {
                return new RInterfaceHL(rloopHandler);
            } catch (REngineException e) {
                // a static initializer cannot throw exceptions
                // but it can throw an ExceptionInInitializerError
                throw new ExceptionInInitializerError(e);
            }
        }

        /**
         * Prevent instantiation.
         */
        private SingletonHolder() {
        }

        /**
         * Get singleton RInterfaceHL.
         * 
         * @return RInterfaceHL singleton.
         */
        public static RInterfaceHL getInstance() {
            return SingletonHolder.INSTANCE;
        }

    }

    /**
     * Return the singleton instance of RInterfaceHL. Only the first call to
     * this will establish the rloopHandler.
     * 
     * @param rloopHandler
     *            R REPL handler supplied by client.
     * @return RInterfaceHL singleton instance
     * @throws REngineException
     *             if REngine cannot be created
     */
    public static RInterfaceHL getInstance(RMainLoopCallbacks rloopHandler)
            throws REngineException {
        RInterfaceHL.rloopHandler = rloopHandler;

        RInterfaceHL instance = null;

        try {
            instance = SingletonHolder.getInstance();
        } catch (ExceptionInInitializerError e) {

            // rethrow exception that occurred in the initializer
            // so our caller can deal with it
            Throwable exceptionInInit = e.getCause();
            throw new REngineException(null, exceptionInInit.getMessage());
        }

        return instance;
    }

    /**
     * org.rosuda.REngine.REngine high level R interface.
     */
    private REngine rosudaEngine = null;

    /**
     * Construct new RInterfaceHL. Only ever gets called once by
     * {@link SingletonHolder.initRInterfaceHL}.
     * 
     * @param rloopHandler
     *            R REPL handler supplied by client.
     * @throws REngineException
     *             if R cannot be loaded.
     */
    private RInterfaceHL(RMainLoopCallbacks rloopHandler)
            throws REngineException {

        // tell Rengine code not to die if it can't
        // load the JRI native DLLs. This allows
        // us to catch the UnsatisfiedLinkError
        // ourselves
        System.setProperty("jri.ignore.ule", "yes");

        rosudaEngine = new JRIEngine(new String[] { "--no-save" }, rloopHandler);
    }
}
4
ответ дан 24 November 2019 в 00:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: