如何解决在抽象类或强制转换中实现子类方法?
假设我有一个超类 Zone
,它用于泛化更具体的 Zone
类型,这些类型在它们各自的子类中定义。
我想创建一个由 4x4 Zone
数组组成的游戏板。玩家应该根据他们所在的 Zone
类型与区域进行不同的互动。
考虑以下超类:
public abstract class Zone{
Pawn pawn;
private boolean movable;
public abstract boolean isMovable();
}
这个类由另外两个类 MountainZone
扩展:
public class MountainZone extends Zone{
private int temperature;
movable = true;
public void FreezePawn(){
super.pawn.freeze(); //suppose freeze() is implemented in Pawn class
}
public boolean isMovable(){
return this.movable;
}
public int getTemperature(){
return this.temperature;
}
}
和LavaZone
:
public class LavaZone extends Zone{
private int sulfurLevels;
private int lavaFlowSpeed;
movable = false;
public boolean isMovable(){
return this.movable;
}
public int getSulfurLevels(){
return this.sulfurLevels;
}
public void setLavaFlowSpeed(int speed){
this.lavaFlowSpeed = speed;
}
}
最后,考虑创建 Main
的以下 gameboard
类:
public final class Main{
private static Zone[][] gameboard = new Zone[4][4];
public static void main (String[] args){
for (Zone z : gameboard){
if (z instanceof MountainZone){
System.out.println(((MountainZone) z).getTemperature());
} else if (z instanceof LavaZone){
System.out.println(((LavaZone) z).getSulfurLevels());
}
}
}
}
我不会在超类中使用 null(或 0 表示 int
)作为 getter 的返回值并在其各自的子类中覆盖它们来编写每个方法,而是倾向于使用如上所示的强制转换。这也适用于 Zone
的子类中的任何其他方法。
我想知道,在特定情况下与 gameboard
数组上的各个区域进行交互的最佳方法是使用强制转换,还是实现从子类到超类的每个唯一方法。
解决方法
简短的回答:反转控制和命令模式的组合。
如果您为所有区域类型提供“getSulphurLevels”方法,这可能很奇怪;它似乎不适用于非熔岩区。当然,它可以工作,但您需要更改应用程序工作方式的思维模型:如果所有区域都有硫含量,但只是在大多数区域中硫含量为 0,那么这可以正常工作,您只需添加:
public int getSulphurLevels() {
return 0;
}
到 class Zone
,并仅在 LavaZone
中覆盖它。尽管如此,该策略并不一定适用于您可能想要对特定区域类型执行的所有奇怪的事情。因此:
控制反转
让我们看看那个 for (Zone z : gameboard)
循环。它试图做什么?它试图打印一些对特定区域特别重要的非常基本的信息。因此,实施THAT:
class Zone {
public String renderImportantInformation() {
return "Nothing special going on here";
}
}
class LavaZone {
public String renderImportantInformation() {
return String.format("Sulphur is at %d density",getSulphurLevel());
}
}
这通常是有用的,但无论如何,如果您想要非通用逻辑,那么您需要决定:要么区域携带此信息,要么董事会携带。通常该区域是正确的位置,但每隔一段时间你就会在顶部获得第三层:代码在 LavaZone
本身中没有意义,但更像是一种组合属性:在特定的电路板类型上,例如,对于特定区域,适用特殊规则。想象一下,您有一个“修改”引擎,可以使用替代规则对游戏进行调整,并且您有一个表示替代规则集的类。这将如何运作?
然后是命令模式:创建一个映射,将相关信息(对于一个简单的模式可能只是区域类型)映射到一个知道如何处理它的代码块上:
private static final Map<Class<? extends Zone>,Function<Zone,String>> pertinentPropertiesPrinters = new HashMap<>();
static {
pertinentPropertiesPrinters.put(LavaZone.class,zone ->
String.format("Sulphur levels: %d",((LavaZone) zone).getSulphurLevel());
}
有点不幸的是,泛型不够强大,无法让您避免此处的强制转换,尽管在实践中您可以通过为给定区域添加一个“处理程序”的单一方法来解决这个问题,该方法负责处理铸造一次。
命令模式有点高级 - 在您使用这些之前还有更多内容需要阅读:我想我会给您它们是什么的一般概念,但我会首先尝试制作能够准确描述您的更一般事物的方法正在尝试执行的操作(例如:打印相关信息、检查危险、询问玩家是否要执行属于该区域的特殊动作等)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。