我有这些接口:
public interface IShipOwner {}
public interface ICitizen {}
public interface IPlayer extends ICitizen, IShipOwner {}
public interface IAIPlayer exends IPlayer {}
此外,我在同一类中有这两个方法:
public boolean isHumanPlayer(ICitizen citizen) {
if (citizen instanceof IPlayer) {
if (citizen instanceof IAIPlayer) {
return false;
} else {
return true;
}
}
return false;
}
public boolean isHumanPlayer(IShipOwner shipOwner) {
if (shipOwner instanceof IPlayer) {
if (shipOwner instanceof IAIPlayer) {
return false;
} else {
return true;
}
}
return false;
}
当使用类型 IPlayer
的对象调用 isHumanPlayer
时,我必须将其转换为类型 ICitizen
或 IShipOwner
以明确应调用哪个方法。
从客户端的角度来看,调用这些方法的最佳方法是什么?如果可能的话,我确实希望避免在保留方法重载的同时强制转换参数的需要。
- 让公民实施
IShipOwner
即使不是每个IShipOwner
都是ICitizen
,反之亦然。 - 使用不同的方法名称。
- 我没有想到的其他事情。
测试对象的功能是一种代码异味。 这意味着您没有使用语言中内置的OO功能。 您可能应该完全摆脱isHumanPlayer
方法。 然后,无论您在哪里测试isHumanPlayer
并根据结果执行不同的操作,只需在IPlayer
上调用一个方法,该方法根据实现执行不同的操作。
我的建议:
-
interface Player
- 常见行为在这里,包括基于isHumanPlayer
值执行任何操作的方法。 -
interface HumanPlayer extends Player
- 添加仅与人类玩家相关的方法。 -
interface AiPlayer extends Player
- 添加仅与 AI 玩家相关的方法。
HumanPlayer
和AiPlayer
添加的方法应仅由程序中专门将玩家视为人类或 AI 玩家的部分调用。 你很少会觉得有必要投射。 如果这样做,则可能需要在层次结构中向上移动对强制转换对象调用的方法。
根据您描述的现有层次结构,听起来人类和 AI 玩家都是ShipOwner
。 但是ShipOwner
接口的确切位置取决于是否有任何其他类型的Player
不是ShipOwner
,或者任何类型的ShipOwner
不是Player
。
我赞同Kevin Krumwiede的观点。
但是如果你真的必须保持isHumanPlayer()
,那么:
让公民实现IShipOwner,即使不是每个IShipOwner都是ICitizen,反之亦然。
不。 从不。 "如果你去了,你只会找到痛苦。">
使用不同的方法名称。
那行得通,但等于认输,对吧?
我没有想到的其他事情。
这给我们带来了:
-
添加
isHumanPlayer( IPlayer player )
-
想出一个新的接口,它由所有其他接口扩展,也许
IPerson
。 -
isHumanPlayer()
每个界面的一部分。 因此,人类玩家只需返回true
;其他人只会返回false
.
另外请注意,这整个混乱:
public boolean isHumanPlayer(ICitizen citizen) {
if (citizen instanceof IPlayer) {
if (citizen instanceof IAIPlayer) {
return false;
} else {
return true;
}
}
return false;
}
可以重述如下:
public boolean isHumanPlayer(ICitizen citizen)
{
return citizen instanceof IPlayer && !(citizen instanceof IAIPlayer);
}
(这可能是也可能不是你的初衷。