我在为数字生成器实现静态工厂时遇到了困难

时间:2013-09-08 06:25:15

标签: java static singleton utility

我已经阅读了所有关于“不使用静态”的声音,我明白它会减少OOP并搞砸单元测试,并且在多线程时可能会破坏代码。但是,我没有尝试过这些。

我正在构建一个Java单例实用程序,它包含一个用于发出ID的公共静态数字生成器 - 无法复制的数字。我选择了单身,因此它可以跟踪程序生命周期中发出的数字,而不必重建一百万,并且不必担心有人不解除多个实例。初始化有效,但它永远不会超出其第一次调用。

我试过这种方式:

    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;
      }
    }

是的,我已尝试将'final'从所有内容中移除......

在每个实现中,我严格静态地调用或者使用实例(SClass s = SClass.SINGLETON; s.Gen_ID)以及上面描述的静态和对象实现。我只得到任何初始和任何连续调用(任何一种方法)的“1000000”。有人愿意解释这里发生了什么吗?

我不是在问我是否应该实现静态(已经有很多页面已经存在) - 我只是简单地询问如何完成这项工作。虽然我对更优雅的解决方案持开放态度..提前致谢!

3 个答案:

答案 0 :(得分: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());
    }

}

答案 1 :(得分:0)

你可以试试这个

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

无需使用synchronized,因为AtomicInteger是线程安全的。

答案 2 :(得分: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实现,如Peter的示例所示,但我收到了有关静态初始化的编译时错误。我认为反对OOP并将AtomicInteger实现为传统的单例,作为对象的属性是太痛苦了。根据Jon的建议,我已经包含了整个代码而不是快照。随意使用:

 /**
  * 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()

}

此实现的输出正是我所需要的,因为它适用于类的内存驻留的生命周期。对于该属性,我只需要在setUp()重新运行时在测试之间预测JUnit的每个增量 - 这不会从内存中取消引用静态类引用。对于我正在测试的包,这实际上对我有利。这是我从后一个工具的输出中获得的:

> 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与传统方法调用的任何其他对象一样使用,但作为单例。它不仅适用于我需要的东西,而且还能够避免破坏OOP设计。在我适应静态工厂之前,我需要更多的练习。再次感谢你们三个花时间回答我的问题! 〜菲尔