9

我正在开发一个编程游戏,玩家可以访问一个抽象类并将其扩展以控制机器人的行为。因为它是一个编程游戏,所以我试图保护我的游戏基础设施,这样玩家就不会弄乱游戏,而不仅仅是我给他们的课程;为此,我制作了大部分课程final,但现在我无法在单元测试中模拟它们(mockito + testNG)。

所以我想知道,我该如何解决这个问题?有没有办法让类非最终测试,然后final在构建周期的后期以某种方式自动“-ize”它们(我正在使用 maven,以防它与答案相关)。我不想添加另一个外部库或更改我的模拟库。
如果不可能,那么还有第二个问题:让课堂final真的安全吗?我看到了一些可以final从字节码中删除分类器的库,这让我认为final如果可以从已经编译的类中删除它,那可能就没用了

4

5 回答 5

10

首先,你不能通过将事情声明为“最终”来阻止人们弄乱你的游戏。有一些反射技巧和整个代码生成库,只是稍微有点不方便克服这个问题。

所以,输掉决赛,然后你可以使用 jmock 或任何你喜欢的库来制作模拟。

于 2012-10-30T13:06:25.773 回答
2

您始终可以使用委托而不是继承。

public interface Foo {
    // ...
}

public final class FooImpl implements Foo {
    // ...
}

public class MockFooImpl implements Foo {
    private FooImpl delegate;
    // ...
}

但是,在 API 中包含抽象类是个坏主意。界面会更好。

于 2012-10-30T13:21:17.363 回答
2

您最终可以尝试应用自动重构工具,例如Jackpot 3RefactoringNG。我从未测试过它们,但如果采用重构的方式,它们完全有能力做你想做的事。

另一种方法是使用允许模拟决赛和静力学的 Powermock(即使很难,我也不喜欢模拟静力学,因为它表明你的设计有问题)。

于 2012-10-30T16:30:34.270 回答
0

IMO,类被标记为 final 以使其对象不可变。如果你想控制一个类的行为,你将类中的方法标记为私有的,这样它们就不能被覆盖。如果您让它们受到保护,那么有人可以扩展您的类,覆盖这些受保护的方法并将扩展类的实例传递给期望您的类对象作为参数的 API,从而引发修改的行为。因此,您可以将不想公开的方法标记为私有。

您只留下保护/公共方法方面的扩展点,这些方法可以被使用这些类的客户端覆盖以实现自定义行为。

于 2012-10-30T13:07:17.523 回答
0

制作大多数类final是一种很好的做法,因为它们通常不是为通过子类化扩展而设计的。我所知道的所有关于 API 设计的书籍都推荐这样做(“Effective Java”、“Practical API Design”、“API Design for C++”)。这有几个原因是有益的,包括 API 设计者意图的表达、API 的安全演进和死代码的预防(例如,一个好的 IDE 将检测一个final方法何时不使用其参数之一,或者从不抛出子句中列出的检查异常throws——这对于非最终方法是不可能的)。

至于模拟上述类,您只需要使用适当的模拟工具,例如JMockit(我开发它正是因为我想在不牺牲某些 OO/API 设计实践的情况下编写单元测试)。

于 2012-10-30T16:43:00.633 回答