我的问题非常复杂且难以解释,因此我建立了一个较小的示例。它仍然很复杂,但让我尽力而为...
您可以在此处下载完整的示例:https://mega.co.nz/#!400lSbqa!NoyflWYk6uaQToVDEwXyn22Bdcn_6GdTxB6dPUfU5FU
我建议将其导入到您喜欢的IDE中并在其中玩耍。
假设您正在编写多人游戏。它应该拥有一个包含实体的世界。该代码应分为服务器,客户端和共享内容。
我的每个实体均包含3个文件:
基础,其中包含共享的代码和资源,例如名称
客户端,它派生基础并包含渲染等。
服务器端,它也派生基础并包含网络事件等。
因为我只能从一个类派生,但也希望我的客户/服务器实体也有一些共享的代码,所以我尝试使用委托样式的结构。让我们将实际实体命名为[default],用*标记接口,并用extends / implements
标记<-
- *BaseEntity*
- [DefaultBaseEntity] <- *BaseEntity*
- *ClientEntity* <- *BaseEntity*
- [DefaultClientEntity] <- [DefaultBaseEntity], *ClientEntity*
- *ServerEntity* <- *BaseEntity*
- [DefaultServerEntity] <- [DefaultBaseEntity], *ServerEntity*
这样,我还可以通过鸭式输入访问服务器/客户端特定的实现以及仅持有ClientEntity / ServerEntity的基本实现。
现在,我要对包含这些实体的世界进行编程。世界范围的代码也应分为三部分,并且应通用以包含服务器或客户端实体。
package base;
import java.util.ArrayList;
import java.util.List;
public abstract class BaseWorld<E extends BaseEntity> {
private List<E> entities;
public BaseWorld() {
entities = new ArrayList<>();
}
public void addEntity(E entity) {
entity.setWorld(this);
entities.add(entity);
}
public List<E> getEntities() {
return entities;
}
public void doStuffWithBuilding(E entity) {
entity.doBasestuff();
}
}
package client;
import base.BaseWorld;
public class ClientWorld extends BaseWorld<ClientEntity>{
}
package server;
import base.BaseWorld;
public class ServerWorld extends BaseWorld<ServerEntity> {
}
如您所见,我为我的实体提供了对其所处世界的反向引用。这包含了实际的问题。
看一下相应的实体代码:
package base;
public class DefaultBaseEntity implements BaseEntity {
private BaseWorld world;
@Override
public void doBasestuff() {
System.out.println("I am base entity");
}
@Override
public void setWorld(BaseWorld world) {
this.world = world;
}
@Override
public BaseWorld getWorld() {
return world;
}
}
现在可以使用,但是BaseWorld是原始类型。显然,每个IDE都开始抱怨。我也不想抑制警告。
我也不能使用
BaseWorld<? extends BaseEntity>
这样的通配符类型,因为当我调用doStuffWithBuilding()这样的世界方法时,它们会产生编译错误:package client;
import base.DefaultBaseEntity;
public class DefaultClientEntity extends DefaultBaseEntity implements ClientEntity {
@Override
public void doClientstuff() {
System.out.println("I am client");
getWorld().doStuffWithBuilding(this);
}
}
方法doStuffWithBuilding(?capture#1-of?extended BaseEntity)在
BaseWorld类型不是
适用于参数(DefaultClientEntity)
有什么解决办法吗?我尝试从基本接口中删除set / getWorld()并将其添加到客户端和服务器中,但这非常笨拙,并且由于委派而导致很多麻烦。
最佳答案
您可以通过参数化DefaultBaseEntity来解决此问题:
public class DefaultBaseEntity <E extends BaseEntity>
implements BaseEntity<E> {
private BaseWorld<E> world;
// ...
}
public class DefaultClientEntity extends DefaultBaseEntity<ClientEntity>
implements ClientEntity {
// ...
}
请注意,即使
DefaultClientEntity
的超类是必需的,也不必对其进行参数化(至少不需要为此设置参数)。更新:
此外,您可以使用接口执行类似的参数化:
interface BaseEntity <E extends BaseEntity> {
public void setWorld(BaseWorld<E> world);
// ...
}
interface ClientEntity extends BaseEntity<ClientEntity> {
// ...
}
上面的示例
DefaultBaseEntity
代码已更新为实现该通用BaseEntity
接口。