繁体   English   中英

在抽象 class 或强制转换中实现子类方法?

[英]Implementing subclass methods in abstract class or casting?

假设我有一个超类Zone ,它的目的是概括更具体的Zone类型,这些类型在各自的子类中定义。 我希望创建一个游戏板,它由一个 4x4 Zone阵列组成。 玩家应该根据他们所在的Zone类型以不同的方式与区域互动。

考虑以下超类:

public abstract class Zone{        
        Pawn pawn;
        private boolean movable;

        public abstract boolean isMovable();
}

这个 class 由另外两个类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(或int为 0)作为 getter 的返回值并在它们各自的子类中覆盖它们,不如在超类中编写每个方法,而是倾向于使用如上所示的强制转换。 这也适用于Zone子类中的任何其他方法。

我想知道,如果gameboard与特定情况下与游戏板阵列上的各个区域进行交互的最佳方法是使用强制转换,或者实现从子类到超类的每一个唯一方法。

简短的回答:反转控制和命令模式的组合。

如果您为所有区域类型提供“getSulphurLevels”方法,那可能很奇怪; 它似乎不适用于非熔岩区。 当然,它可以工作,但你需要改变你的应用程序如何工作的心理 model:如果所有区域都有硫含量,但只是在大多数区域它是 0,那么这工作正常,你可以添加:

public int getSulphurLevels() {
    return 0;
}

class Zone ,并仅在LavaZone中覆盖它。 尽管如此,该策略并不一定适用于您可能想要对特定区域类型执行的所有奇怪事情。 因此:

控制反转

让我们看一下for (Zone z: gameboard)循环。 想做什么? 它试图打印一些对该特定区域特别重要的非常基本的信息。 所以,实现那个

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本身中并没有真正意义的代码,而是更多的组合属性:在特定的板类型上,对于特定的区域,比如说,适用特殊规则。 想象一下,您有一个“修改”引擎,可以使用备用规则调整游戏,并且您有一个代表备用规则集的 class。 那将如何运作?

然后是命令模式:创建一个 map,将相关信息(对于简单的模式,可能只有区域类型)映射到知道如何处理它的代码块上:

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());
}

有点不幸的是,generics 功能不够强大,无法让您避免此处的强制转换,但在实践中,您可以通过为给定区域添加“处理程序”的单一方法来解决此问题,该处理程序会处理一次强制转换。

命令模式有些高级 - 在您使用这些之前还有更多内容需要阅读:我想我会给您一个关于它们是什么的大致概念,但我会首先尝试制作能够准确描述您尝试的更一般事物的方法做(例如:打印相关信息、检查危险、询问玩家是否要执行属于该区域的特殊动作等)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM