2013-09-08 3 views
0

Я прочитал все крики для «не использовать статические», и я понимаю, что он уменьшает ООП и закручивает модульные тесты и может нарушать код, когда мульти -threading. Однако я никого из них не пытаюсь.У меня возникли трудности с внедрением статической фабрики для генератора чисел

Я создаю утилиту singleton Java, которая содержит генератор открытого статического числа для выдачи идентификационных номеров, которые не могут быть дублированы. Я выбрал синглтон, чтобы он мог отслеживать номера, выпущенные на протяжении всей жизни программы, без необходимости восстановления миллиона, и беспокоиться о том, что кто-то не удаляет ссылки на несколько экземпляров. Инициализация работает, хотя она не когда-либо приращение за пределами его первого вызова.

Я пробовал так:

public class SClass { 
     public static final SClass SINGLETON = getInstance(); 
     ... 

     public static final int GEN_ID = genID(); 
     private static int base = 999999; 

     ... 
     ... 

     private static int genID() { 
     SClass.SINGLETON.base += 1; 
     return base 
     } 
    } 

, и я попытался это так:

public class SClass { 
     public static final SClass SINGLETON = getInstance(); 
     ... 

     public static int GEN_ID = genID(); 
     private int base; 
     ... 

     private SClass() { 
     ... 
     this.base = 999999; 
     ... 
     } 

     ... 
     ... 

     private int genID() { 
     this.base += 1; 
     return base; 
     } 
    } 

Да, я пытался сделать это с «окончательным» удален от всего. ..

В каждой реализации я вызываю либо строго статически, либо я использую экземпляр (SClass s = SClass.SINGLETON; s.Gen_ID) с описанными выше как статическими, так и объектными реализациями. Я получаю только «1000000» как с любыми начальными, так и с любыми последовательными вызовами (любой методологии). Кто-нибудь захочет объяснить, что здесь происходит?

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

+1

Ваш код даже не будет скомпилирован, так как во втором случае вы пытаетесь вызвать метод экземпляра ('genID') из статического инициализатора, а в первом случае вы не видите полуточку на конец 'genID'. Мы не пытаемся найти ошибки в коде, который * не является * кодом, который вы используете. Пожалуйста, покажите короткую, но * полную * программу, демонстрирующую проблему. –

+0

Я понял, что псевдокода будет достаточно, чтобы охватить сферу моего вопроса. У моего класса не было проблем с компиляцией в r/l, но спасибо за советы – ToFue

+0

Но как бы вы ожидали, что мы увидим, что не так с вашим * реальным * кодом, когда мы не можем видеть этот код? В будущем, пожалуйста, * работайте над предоставлением короткой, но полной программы. Вам повезло, что на этот раз Питер смог дать совсем другое решение, но мы до сих пор не знаем, что было не так с вашим исходным кодом. –

ответ

0

Вы могли бы попробовать это

class SClass { 
    static final AtomicInteger COUNTER = new AtomicInteger(); 
    final int id = 1000000 + COUNTER.getAndIncrement(); 
} 

Нет необходимости использовать синхронизированные в AtomicInteger является поточно.

+0

Это было очень полезно, Питер, хотя я не смог реализовать статически. Однако ваш совет заставил меня соответствовать ООП, используя AtomicInteger в объекте, который будет вызван через singleton. – ToFue

+0

... Я тщетно пытался использовать счетчик так же, как я вызывал синглтон. Было бы разумно, что отношение экземпляра объекта не может получить обновленный результат метода статического класса, потому что экземпляр был создан с начальным значением и «dis-join» из класса при создании экземпляра, принимающего только одно начальное значение. Спасибо, что указали на меня! (извините за двойной комментарий - я не привык к пятиминутному правлению) – ToFue

0

попробовать это

public class IdGenerator { 


    public static IdGenerator generator = new IdGenerator();  
    private IdGenerator(){} 
    private static int currentID=0; 
    private int getNextID(){ 
     synchronized (this) { 
      currentID=currentID+1; 
     } 
     return currentID; 
    } 

    public static IdGenerator getInstance(){ 
     return generator; 
    } 

    public static void main(String[] args) { 
     IdGenerator generator = IdGenerator.getInstance(); 
     for(int i=0;i<10;i++) 
      System.out.println(generator.getNextID()); 
    } 

} 
+0

Спасибо, это в значительной степени, как я закончил реализацию, за исключением того, что я сделал AtomicInteger как обычный экземпляр var, инициализировал в конструкторе и имел открытый метод для возврата приращения, не статического. Однако я исследую эту модель более подробно. Спасибо за предложение! – ToFue

0

Спасибо Jon, Peter и Upog за помощь в решении моей проблемы. Я хотел показать реальный код для моей исходной проблемы, а затем показать код для того, что его решило, в надежде, что другие могут извлечь выгоду из этого конкретного случая.

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

/** 
* Generate numbers and increment 
*/ 
public class BuggedGenerator { 

    /************** Public Constants/Factory ***********/ 
    private static BuggedGenerator INSTANCE = null; // to contain the single instance 

    /** 
    * The single instance of BuggedGenerator. 
    */ 
    public static final BuggedGenerator READ_IN = getInstance(); 
    public static final int GEN_ID = genID(); 
    private static int base = 999999; 

    /************ Singleton SetUp ************/ 

    /** 
    * Utility Constructor. 
    */ 
    private BuggedGenerator() { 
    super();      // unnessesary, but I always invoke super() 
    } 

    /** 
    * Initialize the counter singleton 
    */ 
    private static int genID() { 
     BuggedGenerator.SINGLETON.base += 1; 
     return base 
     } 

    /** 
    * Determine whether BuggedGenerator already has an instance 
    * and return that instance. 
    */ 
    public static BuggedGenerator getInstance() { 
    if (null == BuggedGenerator.INSTANCE) { 
     BuggedGenerator.INSTANCE = new BuggedGenerator(); 
    } 
    return BuggedGenerator.INSTANCE; 
    } // end getInstance() 
} 

Это то, что я получаю от этой реализации:

> BuggedGenerator.READ_IN.GEN_ID 
> 1000000 
> BuggedGenerator.READ_IN.GEN_ID 
> 1000000 
> BuggedGenerator b = BuggedGenerator.READ_IN 
> b.GEN_ID 
> 1000000 

В ответе на запрос с помощью, я использовал класс AtomicInteger для замены реализации GEN_ID, как показано в примере Питера, но я получил ошибки времени компиляции в отношении статических инициализаций. Я решил, что было слишком много боли, чтобы идти против ООП и реализовал AtomicInteger как обычный синглтон, являющийся свойством объекта. По предложению Перна я включил весь код вместо моментального снимка. Вы можете использовать:

/** 
    * Copyright 2013, Phil Reason. preason intisive com 
    * Permission to copy, modify, resell and or freely distribute - provided an 
    * exact copy of this file is explicitly accompanied and unaltered alongside 
    * of any distribution of works using this file or any modified version of 
    * this file. 
    */ 

import java.util.concurrent.atomic.AtomicInteger; 

/** 
* This is a class to generate numbers for various purposes. 
* @author   Phil Reason 
* @conceptionDate 9/6/13 
* @version   1.1 
* @revisionDate 9/8/13 
*/ 
public class Generator { 
    /************** Constants *********************/ 
    /** 
    * The single instance of Generator. 
    */ 
    public static final Generator READ_IN = getInstance(); 
    private static Generator INSTANCE = null; // to contain the single instance 
    /******** Instance Vars: *******************/ 
    private AtomicInteger counter;    // construct an AtomicInteger 
    private int iDRange; 

    /************ Singleton SetUp ************/ 
    /** 
    * non-public default constructor override. 
    */ 
    private Generator() { 
    super();      // unnessesary, but I always invoke super() 
    this.iDRange = 1000000;  // the starting number to range increments 
    this.counter = new AtomicInteger(); // the AtomicInteger instance 
    } //END Generator() 

    /** 
    * Determine whether Generator already has an instance 
    * and return that instance. 
    */ 
    private static Generator getInstance() { 
    if (null == Generator.INSTANCE) {   // upon first use... 
     Generator.INSTANCE = new Generator(); // construct the single instance 
    } 
    return Generator.INSTANCE;     // return ony that instance 
    } // END Generator getInstance() 

    /** 
    * Generate non-repeating numbers. This can be useful for serializing when 
    * inherited serialization isn't useful or needed. 
    * 
    * Return the current count generation then increment the AtomicInteger. 
    * @ensure genID() >= 1000000 && genID() != genID() (never repeats a number) 
    */ 
    public int genID() { 
    return iDRange + counter.getAndIncrement(); // increments the sum of counter 
    } // END int genID() 

} 

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

> Generator.READ_IN.GEN_ID 
> 1000000 
> Generator.READ_IN.GEN_ID 
> 1000001 
> Generator b = Generator.READ_IN 
> b.GEN_ID 
> 1000002 
... and so on ... 

В этом РЕАЛИЗАЦИИ AtomicInteger используется в качестве, как и в любом другом объекте с традиционным вызовом метода, хотя, как одноплодные. Мало того, что это работало для того, что мне было нужно, но я также смог избежать нарушения дизайна ООП. Мне понадобится больше практики, прежде чем я буду достаточно удобен, чтобы совершить статические фабрики. Еще раз спасибо вам три за то, что вы нашли время ответить на мой вопрос! ~ phil