Шаблон дизайна Singleton и предотвращение клонирования - PullRequest
24 голосов
/ 16 февраля 2012

Во многих статьях, которые я читал в сети о шаблоне разработки Singleton, упоминается, что класс должен переопределить метод clone (), и в нем выдается исключение CloneNotSupported.Действительно ли это необходимо?

Метод clone () по умолчанию защищен, поэтому ни один класс (кроме тех, которые находятся в одном пакете) не сможет вызвать его в этом экземпляре Singleton.Кроме того, если этот Singleton не реализует Cloneable, то даже если этот метод вызывается, он выдаст исключение во время выполнения.Кроме того, поскольку конструктор является частным, мы не сможем его разделить на подклассы и тем самым разрешить его клонирование.Так должен ли я по-прежнему реализовывать этот совет для своих классов в Синглтоне?

РЕДАКТИРОВАТЬ: Просто чтобы уточнить: я не ищу наилучшего возможного способа реализации Синглтона.Я просто спрашиваю о справедливости упомянутого выше совета относительно «обычного» шаблона Singleton (а не Singleton на основе Enum).

Ответы [ 10 ]

24 голосов
/ 16 февраля 2012

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


РЕДАКТИРОВАТЬ: Просто чтобы уточнить: я не ищу лучший возможный способ реализации Singleton. Я просто спрашиваю о справедливости упомянутого выше совета, относительно "нормального" шаблона Singleton (а не Singleton на основе Enum).

Поскольку у вас Effective Java, , вы уже должны знать о подводных камнях и проблемах с Cloneable. Тем не менее, если вы собираетесь реализовать синглтон одним из «неправильных» способов, нет, нет абсолютно никаких причин для реализации Cloneable и переопределения Object#clone(), просто чтобы бросить CloneNotSupportedException. Object#clone() уже делает это , когда интерфейс Cloneable отсутствует.

8 голосов
/ 07 августа 2013

@ shrini1000, у вас правильный вопрос, но предложение о клоне очень специфично для следующего условия

public Object clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException(); 
}

Вышеприведенное необходимо только в том случае, если суперкласс класса-одиночки реализует публичный клон() метод .

3 голосов
/ 09 сентября 2014

Приведенный ниже код предназначен для предотвращения клонирования одноэлементного класса. Переопределите метод clone и добавьте новое CloneNotSupportedException ()

public final class SingeltonCloneTest implements Cloneable {

    /**
     * @param args
     * @return
     */
    private static SingeltonCloneTest instance = null;

    private SingeltonCloneTest() {
     System.out.println("Rahul Tripathi");
    }

    public static SingeltonCloneTest getInstance() {

        if (instance == null) {
            instance = new SingeltonCloneTest();
            return instance;
        }
        return instance;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {

        // TODO Auto-generated method stub
        /*
         * Here forcibly throws the exception for preventing to be cloned
         */
        throw new CloneNotSupportedException();
        // return super.clone();
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        SingeltonCloneTest test1 = SingeltonCloneTest.getInstance();

        try {
            SingeltonCloneTest test2 = (SingeltonCloneTest) test1.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
2 голосов
/ 22 ноября 2013

Вы можете избежать клонирования, передав уже созданный объект методом клонирования.

public Object clone() {

return singletoneObject;

}
2 голосов
/ 24 февраля 2013

Это необходимо, если ваш класс Singleton расширяет класс с видимым методом clone (), определенным в его иерархии.

2 голосов
/ 16 февраля 2012

При написании класса с использованием шаблона Singleton, только один экземпляр этот класс может существовать одновременно. В результате класс не должен быть разрешено делать клона.

Шаблон singleton говорит, что внутри программы существует только один экземпляр класса, поэтому правильно вызывать CloneNotSupportedException в методе Clone ().

2 голосов
/ 16 февраля 2012

См. https://stackoverflow.com/a/71399/385478 для самого безопасного способа применения шаблона Singleton.По сути, сделайте ваш Singleton enum, а не class, с одним значением INSTANCE.

1 голос
/ 20 мая 2015

Лучший пример, который я нашел, это:

class SingletonSuper implements Cloneable {
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
   }
}

class Singleton2 extends SingletonSuper {
    // 1. Make all constructors private
    private Singleton2() {
     }

// 2. Declare a private static variable to hold single instance of class
    private static Singleton2 INSTANCE = new Singleton2();

    public static Singleton2 getInstance() {
        return INSTANCE;
   }
  }

 public class SingletonCloningTest {
    public static void main(String[] args) throws Exception {
        System.out.println("Singleton Test!");
         System.out.println("Singleton Instance:" +                         +  Singleton2.getInstance());
        System.out.println("Singleton clone:"
            + Singleton2.getInstance().clone());
    }
}



 The result will:

 Singleton Test!
 Singleton Instance:com.sample.test.Singleton2@50d89c
 Singleton clone:com.sample.test.Singleton2@1bd0dd4
0 голосов
/ 06 июля 2016

Насколько я понимаю, вам не нужно реализовывать метод clone (). Причина: 1. Если вы не реализуете метод clone и интерфейс Cloneable, он выдаст исключение CloneNotSupportedException. 2. метод клонирования защищен, и вы не можете создать подкласс одноэлементного класса.

0 голосов
/ 25 октября 2012

Вам необходимо переопределить метод clone(), только если ваш одноэлементный класс реализует интерфейс Cloneable или класс, который реализует интерфейс Cloneable.

...