TL; DR:我希望超类能够调用子类中的函数,而不需要不同的子类能够调用彼此的重写函数。我可以用一个Handler接口来实现这一点,子接口实例化后调用私有方法,但感觉很乱(见下面的代码)。有没有更好的办法?创建方法的最好方法是什么,只有超级(而不是其他子类)可以调用它们?
我正在写一个简单的Java游戏,玩家将在学习编程时由学生编写游戏。游戏是一对一的,每个玩家都会告诉游戏引擎他们想要采取什么行动,并在周围定购单位。
我试图让游戏允许学生调用任何对他们可见的函数。目标是缺乏反思,无法作弊。在大多数情况下,这可以通过将Player子类放在与游戏引擎不同的包中轻松完成。
我遇到的问题是我需要玩家重写诸如doTurn,endGame和newGame等方法。但是,没有办法让这些可见的被覆盖,而不会让其他玩家可以看到它们。玩家需要能够互相访问以检查单位所有权等。
我现在的解决方案是有一个接口让子类把它们的方法包装进来,以便超类可以调用它们。
public abstract class Player {
public final String NAME;
private Handler handler;
public Player(String name) {
handler = getHandler();
NAME = name; // note this is initialized AFTER handler
}
protected abstract Handler getHandler();
// can be called by stuff in this package (engine)
// but not another package (where players are)
void doTurn() {
handler.doTurn();
}
protected interface Handler {
void doTurn();
}
}
另一个包
...
public class BasicPlayer extends Player {
public BasicPlayer() {
super("BasicPlayer");
}
private void secretStrategies() {
// Actual logic goes here
}
@Override
protected Handler getHandler() {
// Null check makes handler only visible during super
return NAME != null ? null : new Handler() {
@Override
public void doTurn() {
secretStrategies();
}
};
}
}
我想初始化处理程序传递到超级匿名类,但不起作用,因为那么就不能“指的是实例方法/字段,同时显式调用构造函数。“也就是说,直到超级构造函数实际发生时,BasicPlayer和Player实例还不存在。因此,为了避免玩家访问彼此的处理程序,getHandler必须仅适用于super,所以NAME!= null就在那里。这对我来说真的很难受。如果我能够通过匿名课程,即使它仍然有点不可思议,但感觉不会太差。除了是非常奇怪的设计之外,我不能让玩家把他们所有的变量/逻辑放到一个匿名的Handler中传递给超级构造器,因为在Player中有函数需要他们调用,而这些函数是即使声明为final(仍然是“实例方法”)(这对编译器来说是有意义的,但仍然令人讨厌)。
有没有更好的实现方法?
如果没有更多信息,很难提供建议。但是:1.如果两个玩家PlayerA和PlayerB都在自己的包中,那么'PlayerB'不应该仅仅通过引用'Player'来调用PlayerA的'doTurn()'。 2.我会避免让'玩家'互相访问。如果他们需要检查“单位所有权”等,则通过游戏引擎的API来执行。 –
@AdrianShum这实际上是很好的方式,并且JCL中有很多示例([示例](https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html#addAll- java.util.Collection-))。你所要做的就是指定一个不同的接口用于与对象交互。查看我的回答 –
@VinceEmigh对不起,我不知道你的评论是指哪一点我的意见 –