如何创建两个Java类的接口只读一个,一个读写?

我正在用Java编写游戏引擎,用于双人纸牌游戏,我的学生将为其编写AI玩家。

AI玩家将把扑克牌轮流放到他们面前“桌子”一部分的“场地”上。 他们可以用自己场上的牌攻击另一个玩家场上的牌。 卡片可以面朝上或面朝下。

GameEngine类通过调用GamePlayer.TakeTurn(GameEngine eng)方法允许AI玩家轮到他/她。 玩家可以向游戏引擎询问防守玩家的场地,以便玩家可以根据那里的牌数以及哪些牌面朝上来做出决定。 假设这个方法是GameEngine.GetDefendingField()

现在,我想确保攻击玩家无法修改防御玩家的场地或防御玩家场地中的牌,并且攻击玩家只能识别防御玩家区域中的正面朝上牌。

我有Card,Field(一个ArrayList of Cards),GamePlayer和GameEngine的课程。 有没有办法为Field创建一个界面,以便GameEngine可以返回防守玩家的场地而攻击玩家无法改变它? 并且没有攻击玩家能够将防守球员的场地改造成可以改变的东西。

我可以让GameEngine.GetDefendingField()返回一个无法重新转换为字段的字段的只读接口吗?

TIA,

SH-

如果要在不复制的情况下实现此目的,并且无法将只读接口引用强制转换为相应的读写接口,则可以尝试使用包装器方法。

对于这样的界面:

interface Info { String getInfoA(); void setInfoA(String infoA); String getInfoB(); void setInfoB(String infoB); } 

您可以创建一个只读包装器,它忽略setter或throwsexception,例如:

 class ReadonlyInfo implements Info { final Info instance; ReadonlyInfo(Info info) { if (null == info) { throw new InvalidArgumentException(); } instance = info; } String getInfoA() { return instance.getInfoA(); } void setInfoA(String infoA) { /** silent ignore */ } String getInfoB() { return instance.getInfoB(); } void setInfoB(String infoA) { throw new IllegalStateException(); } } 

通过使用包装器方法,您可以在客户端使用多态,可以安全地反对转换引用以获得更多访问权限,并在静默忽略调用setter或抛出非法访问exception之间进行选择。

注意:当然,对于使用reflection来检索包装对象的代码,您将无法安全。

你在这里谈论基本的模型 – 视图 – 控制器,你的模型是卡片和场,控制器是GamePlayer和GameEngine,而视图尚未定义。 您的Field是您的模型,您可能希望创建两个不同的接口来访问Field模型,一个是只读的,一个是读写的。 您的读写实现可能只返回Field对象。 您的只读实现将通过字段中的元素进行翻录,并仅返回他们有权访问的元素,对返回的字段中的每个卡执行深层复制。

我喜欢在编译时使用类型安全和多态来控制这种访问控制的想法,特别是在教学时。

接近它的一个好方法是拥有两个Field接口。 也许是Field和MutableField,后者扩展了前者并添加了更改方法。 你的FieldImpl当然可以同时实现。

当然,问题是您希望根据您使用的字段从游戏引擎返回不同的声明类型(Field或MutableField)。 如果你有一个模型,你可以使用类似getMyField()和getOtherPlayerField()的东西,因为从描述中可以看出,在调用getField()时,人们确切地知道它们想要的字段。

您可以创建只有getter的只读接口。 扩展该接口将是添加setter的读写器接口。

你绝对可以做到这一点。 这是一种在对象能力文献中称为衰减的方法。 只要限制类型未定义为强类型的子类型,则转换对象将不会提供更多权限。

您无法定义强制对字段/成员进行只读访问的Java接口,因为这是在类中定义的实现细节。 (实际上,如何在内部存储数据是一个实现细节)

我建议创建两个Field接口的实现,一个具有只读访问权限,另一个具有读取/编辑function。 您可以让每个类实现Field接口,也许使用AbstractField类作为每个类的父类来覆盖常用function。

然后,您可以为每个具体类(只读和读/写)创建构造函数,以便在必要时在两者之间进行转换。

你可以创建两个合同 – 一个允许get和set,另一个只支持get。

例)

  public interface Info { void setA(String data); String getA(); } public interface ReadableInfo { String getA(); } public class ReadableInformation implements ReadableInfo { private Info underlyingInfo; public ReadableInformation(Info info) { this.underlyingInfo = info; } @Override public String getA() { return underlyingInfo.getA(); } } 

有了这个,您可以将可变合同( Info )转换为仅支持访问器( ReadableInfo )的合同。 但这需要根据客户端的人员移交不同类型的对象( Info vs ReadableInfo )。