简体   繁体   English

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

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

Suppose I have a superclass Zone , which serves the purpose of generalizing more specific types of Zone which are defined in their own respective subclasses.假设我有一个超类Zone ,它的目的是概括更具体的Zone类型,这些类型在各自的子类中定义。 I wish to create a game board, which consists of a 4x4 Zone array.我希望创建一个游戏板,它由一个 4x4 Zone阵列组成。 A player should interact with a zone differently depending on what type of Zone they are on.玩家应该根据他们所在的Zone类型以不同的方式与区域互动。

Consider the following superclass:考虑以下超类:

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

        public abstract boolean isMovable();
}

This class is extended by two other classes, MountainZone :这个 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;
        }
}

and LavaZone :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;
        }
}

Lastly, consider the following Main class where the gameboard is created:最后,考虑创建游戏板的以下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());
            }
        }
    }
}

Instead of writing each method in the superclass with null (or 0 for int ) as the return value for the getters and overriding them in their respective subclasses, I would tend towards using casting as shown above.与其在超类中使用 null(或int为 0)作为 getter 的返回值并在它们各自的子类中覆盖它们,不如在超类中编写每个方法,而是倾向于使用如上所示的强制转换。 This applies for any other method in the subclasses of Zone as well.这也适用于Zone子类中的任何其他方法。

I want to know, if the best way to go about interacting with the individual zones on the gameboard array for specific cases is to use casting, or to implement every single unique method from the subclasses to the superclass.我想知道,如果gameboard与特定情况下与游戏板阵列上的各个区域进行交互的最佳方法是使用强制转换,或者实现从子类到超类的每一个唯一方法。

The short answer: A combinatino of Invert control, and command patterns.简短的回答:反转控制和命令模式的组合。

If you give all zone types the 'getSulphurLevels' method, that's potentially odd;如果您为所有区域类型提供“getSulphurLevels”方法,那可能很奇怪; it doesn't appear to apply to a non-lava zone.它似乎不适用于非熔岩区。 It can work, of course, but you need to change the mental model of how your app works: If ALL zones have a sulphur level, but it's just that on most zones it is 0, then this works fine, and you can just add:当然,它可以工作,但你需要改变你的应用程序如何工作的心理 model:如果所有区域都有硫含量,但只是在大多数区域它是 0,那么这工作正常,你可以添加:

public int getSulphurLevels() {
    return 0;
}

to class Zone , and override that only in LavaZone .class Zone ,并仅在LavaZone中覆盖它。 Still, that strategy doesn't neccessarily apply to all the weird things you might want to do to a specific zone kind.尽管如此,该策略并不一定适用于您可能想要对特定区域类型执行的所有奇怪事情。 Thus:因此:

Inversion of control控制反转

Let's look at that for (Zone z: gameboard) loop.让我们看一下for (Zone z: gameboard)循环。 What is it trying to do ?想做什么? It is trying to print some very basic information that is of particular importance to that specific zone.它试图打印一些对该特定区域特别重要的非常基本的信息。 So, implement 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());
    }
}

This usually serves, but one way or another, if you want non-universal logic, then you need to decide: Either the zones carry this info, or the board does.这通常是有用的,但是一种或另一种方式,如果你想要非通用逻辑,那么你需要决定:要么区域携带此信息,要么董事会携带。 Usually the zone is the right place, but every so often you get a third layering on top: Code that doesn't really make sense to be in LavaZone itself, but is more a combinatorial property: On specific board kinds, for specific zones, say, special rules apply.通常区域是正确的位置,但每隔一段时间你就会在顶部获得第三层:在LavaZone本身中并没有真正意义的代码,而是更多的组合属性:在特定的板类型上,对于特定的区域,比如说,适用特殊规则。 Imagine you have a 'modification' engine where the game can be tweaked with alternate rules, and you have a class representing the alternate ruleset.想象一下,您有一个“修改”引擎,可以使用备用规则调整游戏,并且您有一个代表备用规则集的 class。 How would that work?那将如何运作?

Then there is the command pattern: Create a map that maps the pertinent info (perhaps only the zone type, for a simple pattern) onto a block of code that knows what to do with it:然后是命令模式:创建一个 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());
}

It is slightly unfortunate that generics aren't powerful enough to let you avoid the cast here, though in practice you can paper over this by making a single method for adding a 'handler' for a given zone which takes care of the casting once.有点不幸的是,generics 功能不够强大,无法让您避免此处的强制转换,但在实践中,您可以通过为给定区域添加“处理程序”的单一方法来解决此问题,该处理程序会处理一次强制转换。

Command patterns are somewhat advanced - there's more to read before you use these: I thought I'd give you a general idea of what they are, but I'd try first with making methods that accurately describe the more general thing you are trying to do (such as: Print pertinent information, check for hazards, ask the player if they want to perform the special action that belongs with this zone, etc).命令模式有些高级 - 在您使用这些之前还有更多内容需要阅读:我想我会给您一个关于它们是什么的大致概念,但我会首先尝试制作能够准确描述您尝试的更一般事物的方法做(例如:打印相关信息、检查危险、询问玩家是否要执行属于该区域的特殊动作等)。

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

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