Java 如何设计一个可用于测试的伪随机数发生器模式?

Java 如何设计一个可用于测试的伪随机数发生器模式?,java,design-patterns,random,software-design,Java,Design Patterns,Random,Software Design,我目前开发了一个相当大的应用程序,其中包括计算数学问题。计算是在类中进行的,我们称它们为A和B,它们有一些随机的最终属性和一个(唯一的)最终int-id作为实例变量 我希望能够在测试模式下运行程序,在每次执行中,随机变量完全相同,例如,允许我使用Junit测试将结果与手工计算进行比较。显然,我不想在每次代码更改后重新计算我的示例解决方案(例如,如果插入了对prng的早期访问,这将移动所有随机数) 请注意,我目前使用Java.util.Random作为prng,但我愿意接受建议 现在的问题是:我应

我目前开发了一个相当大的应用程序,其中包括计算数学问题。计算是在类中进行的,我们称它们为A和B,它们有一些随机的最终属性和一个(唯一的)最终int-id作为实例变量

我希望能够在测试模式下运行程序,在每次执行中,随机变量完全相同,例如,允许我使用Junit测试将结果与手工计算进行比较。显然,我不想在每次代码更改后重新计算我的示例解决方案(例如,如果插入了对prng的早期访问,这将移动所有随机数)

请注意,我目前使用Java.util.Random作为prng,但我愿意接受建议

现在的问题是:我应该如何构造prng的实例化和访问?要指出这个问题,请注意,以下是非常糟糕的方法:

  • 我不能让它成为一个单例并从任何地方访问,因为这样,类中的随机数将取决于实例化的顺序
  • 很明显,我不能用硬编码种子来实例化一个新的随机(种子),因为如果程序运行多次(在测试模式之外),数字就不会不同
我提出了以下解决方案(主要基于),但并不完全相同,因为编程语言和测试种子生成是不同的

公共类PRNGeneratorGenerator{
//使班级成为单身学生
私有PRNGeneratorGenerator实例;
专用PRNGeneratorGenerator(){}
公共PRNGeneratorGeneratorGetInstance(){
如果(instance==null)instance=new PRNGeneratorGenerator();
返回实例;
}
//RandomNumberGenerator方法和属性
私有布尔isTestMode=false;
private Random seedRng=new Random();
public void setTestMode(布尔测试模式){
isTestMode=testMode;
}
公共随机getPseudorandomNumberGenerator(长测试种子){
if(isTestMode)返回新的Random(testSeed);
返回新的Random(seedRng.nextLong());
}
}
具有最终随机数的类(上面命名为A和B)将如下所示:

公共A类{
私有最终静态长类_SEED=872349;
私人最终整数随机数;
私有最终整数随机数two;
私有最终int id;
公共A(内部id){
this.id=id;
长testSeed=CLASS_SEED+id;
Random rnd=PRNGeneratorGenerator.getInstance().getPseudorandomNumberGenerator(testSeed);
randomNumberOne=rnd.nextInt();
randomNumberTwo=rnd.nextInt();
}
}
在测试模式中,我会在开始任何实例化之前调用
PRNGeneratorGenerator.getInstance().setTestMode(true)


这是用java解决问题的好方法还是这种方法有任何缺点?我读过许多类似的问题,但没有找到回答我问题的对等问题。提前谢谢你的回答

我建议创建一个类“PRNGeneratorGeneratorTest”,该类创建自己的PRNGeneratorGenerator本地实例进行测试。洗牌测试和生产代码不是一个好主意,原因有很多:例如,它很混乱,很容易在测试代码中留下一些东西,当不需要的时候会打开模式,等等。。无论如何,测试类还有其他好处,比如让您能够在一个构建中同时执行所有测试,并自动显示和保存结果

如果不想创建测试类,至少将getPseudorandomNumberGenerator除以2(即创建测试方法):


…这不是一个很好的实践,但它比混乱测试和生产代码要好得多。

if(testMode)
几乎总是一种气味!依赖注入可能是这里的答案(即,您通过构造函数参数向类提供PRNG)。只是另一个选项,使用任何适应单元测试框架,您可以在表中生成测试数据和结果。你无论如何都需要保留它们,所以用一个固定的种子生成随机数是没有帮助的。@OliverCharlesworth:我也不喜欢它;这就是为什么我觉得我需要把它贴上去收集意见的原因依赖激励看起来是一个非常好的解决方案,我将使用它。谢谢你的评论!你是想发布一个我可以接受的答案并给你评分,还是我应该自己发布一个答案?
public Random getPseudorandomNumberGenerator(){
    return new Random(seedRng.nextLong());
}

public Random getPseudorandomNumberGeneratorTest(long testSeed){
    return new Random(testSeed); 
}