0

我有 0..n 个对象,每个对象都需要一个唯一标识符,它们是通过这种方式创建的:

public class Squirrel {

    private static numSquirrels = 0;

    private String id = null;

    public Squirrel() {
        this(String.valueOf(numSquirrels++);
    }

    public Squirrel(String id) {
        this.id = id;
    }
}

这在几个方面是一个问题,但我会给出一个:

在进行单元测试时,numSquirrels 变量会在测试之间延续,即使我可能正在使用不同的松鼠种群。这意味着当我想重新开始时,他们的 ID 会继续增加。

  • 现在是使用 SquirrelFactory 的正确时间吗(孩子们喜欢的那种)?
  • 我应该使用依赖注入将工厂传递给 Squirrel 对象,还是应该将 Squirrel 类包含在与外部世界有接口的 Squirrel Factory 中?
  • 如果我希望用户能够设置 ID(或至少建议 ID),如何确保唯一性?
4

6 回答 6

3

我认为这个实现会很好,但如果你正在处理并发,你可能应该使用 AtomicInteger。

您的单元测试问题可以通过结合使用模拟并将其包装在另一个类中进行模拟来解决。请参阅这篇文章 How to mock a static variable in java using JMock

或者,一个简单的解决方案是为静态变量公开一个设置器,在测试用例结束时,您可以将其设置回 0,或者任何“重置”对您意味着什么。

于 2013-02-07T19:05:42.553 回答
0

引入一个称为SquirellPopluationSquirrel 工厂的类,将静态计数器移动到它,并使其成为实例变量。

如果您希望工厂的用户能够设置自己的 id,那么请使用 set 而不仅仅是计数器。

于 2013-02-07T19:03:01.580 回答
0

您可以为该类设置一个静态“重置”方法。将其称为测试拆卸(或设置)的一部分。

于 2013-02-07T19:05:53.937 回答
0

松鼠班可能不知道工厂。我建议以下实现:

public interface Squirrel // interface, not class
{
    public String getID ();

    // other methods here
}

public class SquirrelFactory
{
    private int nextSquirrelID = 0;

    public Squirrel createSquirrel ()
    {
        return new SquirrelImpl (String.valueOf (nextSquirrelID++));
    }

    private static class SquirrelImpl implements Squirrel
    {
        private final String id;

        // other fields here

        public SquirrelImpl (String id)
        {
            this.id = id;
        }

        @Overrides
        public String getID ()
        {
            return id;
        }

        // other methods here
    }
}

然后使用createSquirrelaSquirrelFactory而不是构造函数的方法。并为每个单元测试创​​建新的类实例SquirrelFactory

于 2013-02-07T19:13:10.687 回答
0

只是与最后一个问题相关的特定案例:

如果我希望用户能够设置 ID(或至少建议 ID),如何确保唯一性?

如果您想这样做,您必须跟踪所有实例。您可以使用BitSet例如。如果你这样做,你冷提供一种解构器:

/**
 * Eat the squirrel.<br>
 * You can not do anything anymore with the squirrel after it has been eaten,
 * but it can be reborn.
 */
public void eat() { //at least, sounds friendlier than kill, shoot, or whatever
  instances.clear(id);
}

小心,因为这不是像 c++ 那样真正的解构器。您不能(轻松)销毁该对象。它仍然可以使用。那么你应该在内部处理这个问题。

提示:如果你使用多线程代码,live 开始变得复杂。但显然从静态id来看,你没有。

于 2013-02-07T19:25:02.567 回答
0

我认为要满足您的所有要求,您将需要一个 SquirrelFactory 类来获取新的 Id 并确保它们都是唯一的。您可能希望将 SquirrelFactory 设为 Singleton。

SquirrelFactory 的职责是:

  • 跟踪正在使用的 id
  • 根据计数器创建具有新 ID 的松鼠(并确保它是唯一的)
  • 创建具有给定 ID 的松鼠(用于从文件加载时),如果 id 已在使用中,则创建一个新的,如上
  • 将新松鼠的 ID 添加到正在使用的 ID 列表中。
  • 对于测试,您可能需要一种方法来重置计数器和 ID 列表
  • (可选)有办法在移除松鼠时从列表中移除 id
于 2013-02-07T20:29:45.280 回答