Синглтон с инициализацией статического члена - PullRequest
0 голосов
/ 07 ноября 2010

В приведенном ниже фрагменте кода, когда я его изначально проектировал, «следующее число» было необходимо для отправки следующего увеличенного значения во время выполнения приложения. Таким образом, я сделал класс синглтоном. Однако, с некоторыми недавними изменениями в требованиях, мне нужно было сделать сброс на «следующий номер». Я просто добавил метод сброса, чтобы сделать это. Тем не менее, это определенно нарушает шаблон Singleton, и я также знаю, что не стоит так инициализировать статический элемент.

Как вы думаете, что я должен делать вместо этого?

public final class GetNextNumber {
    private static GetNextNumber instance; 
    private static Integer nextNumber=1;
    private GetNextNumber() {
    }
    public static synchronized GetNextNumber getInstance() {
        if(instance==null){
            instance = new GetNextNumber();
        }
        return instance;
    } 
    protected Integer getNextNumber(){
        return nextNumber++;
    }
    protected synchronized void reset(){
        nextNumber=1;
    }
    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }
}

Ответы [ 2 ]

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

Выглядит нормально для меня - за исключением двух вещей:

  • getNextNumber не synchronized.
  • , поскольку getNextNumber и reset не static, nextNumber также не обязательно должно быть static.

Вы можете использовать AtomicInteger, чтобы избежать необходимости применять методы getNextNumber и reset synchronized:

public final class GetNextNumber {

    private static GetNextNumber instance;

    private AtomicInteger nextNumber = new AtomicInteger(1);

    private GetNextNumber() {
    }

    public static synchronized GetNextNumber getInstance() {
        if(instance==null){
            instance = new GetNextNumber();
        }
        return instance;
    } 

    protected Integer getNextNumber(){
        return nextNumber.getAndIncrement();
    }

    protected void reset(){
        nextNumber.set(1);
    }
}

Подробнее об этом см., Например, Классы Atomic в Java 5: AtomicInteger и AtomicLong :

До Java 5 нам приходилось писать классы с доступом к переменной счетчика в synchronized блоков или методов, или иначе используйте volatile переменную, которая более легкая форма синхронизации, но с риском, что некоторые обновления могут будет пропущено, если они происходят одновременно. AtomicInteger может использоваться как вставная замена, которая обеспечивает лучшее из обоих миров ...

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

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

Сброс также не нужно синхронизировать, если только не getNextNumber.

...