创建 Java 子类的层次结构

问题描述 投票:0回答:4

我正在尝试在java中设置位置的层次结构。地点可大可小,较大的地点包含较小的子地点。因此,世界包含国家,国家包含城市,依此类推,具体到建筑物和房间。

我创建了一个名为 Place 的抽象类,它是所有这些类型的父类。每个地点都包含子位置图、父位置以及获取父子位置(也称为邻居)的能力

我遇到的主要问题是一个父级的子位置应该是一个类的实例,但是没有办法用java来指定它。

我考虑过对所有类型进行硬编码,以便 City 的 getParent 返回一个国家/地区,而 getSublocations 返回一个建筑图,但这会在更改类的功能或添加新类时产生一些问题,并且涉及大量的问题代码复制。还有其他方法可以解决这个问题吗?

编辑:

感谢您的所有回答。这是我到目前为止所拥有的。它并不完美,但也不算太糟糕。我必须复制的唯一代码是 getNeighbors() 的实现。它曾经直接在抽象类中实现(this.getParent().getSublocations().getEdges(this)),但这只是一行代码。

import java.util.HashSet;
public abstract class Place {
    //World, Region, City, Building, Room
    public enum Direction {
        East, Northeast, North, Northwest, West, Southwest, South, Southeast, Invalid;
        public static Direction fromInt(int i) {
            switch (i) {
            case 0: return East;
            case 1: return Northeast;
            case 2: return North;
            case 3: return Northwest;
            case 4: return West;
            case 5: return Southwest;
            case 6: return South;
            case 7: return Southeast;
            default: return Invalid;
            }
        }
        public static Direction fromAngle(double angle) {
            return fromInt((int) (angle+22.5)/45);
        }
    }

    protected final int locked = Integer.MAX_VALUE;
    protected int x, y; //longitude and latitude
    public abstract String getName();
    public abstract <S extends Place> Graph<S> getSublocations();
    public abstract <T extends Place> T getParent();
    public abstract <U extends Place> HashSet<Passage<U>> getNeighbors();

    public final Direction getDirection(Place otherPlace) {
        if (otherPlace == null) {
            return Direction.Invalid;
        } else if (this.getClass() == otherPlace.getClass()) {
            return Direction.fromAngle(Math.atan2(otherPlace.y-y, otherPlace.x-x));
        } else {
            return Direction.Invalid;
        }
    }
}
java abstract
4个回答
1
投票

我已经遇到过这个问题好几次了,当你搞乱这样的事情时,我不建议在这种情况下使用泛型,因为你已经知道每个 Place 将返回什么。希望这段代码能有所帮助。

public interface Place {
    // Place can be an abstract class if you want. 
    // Making it abstract could cause some problems because it might make you use generics
    // I recommend an interface
    List<? extends Place> getSublocations();
    Place getParent();
}
public class World implements Place {

    private List<Country> countries;

    @Override
    public List<Country> getSublocations() {
        return this.countries;
    }

    @Override
    public Place getParent() {
        return null;
    }
}
public class Country implements Place {
    private List<City> cities;
    private World parent;

    @Override
    public List<City> getSublocations() {
        return this.cities;
    }

    @Override
    public World getParent() {
        return this.parent;
    }
}
public class City implements Place {
    private Country parent;

    @Override
    public List<? extends Place> getSublocations() {
        return null;
    }

    @Override
    public Country getParent() {
        return this.parent;
    }
}

代码中不应该有太多的复制和粘贴,但我认为这是你最好的选择。


0
投票

假设每种类型都直接从

Place
扩展(而不是像
City extends Country
这样的东西,这是错误的),您应该能够使用泛型来限制您的样板,例如:

public class Place<P extends Place<?, ?>, C extends Place<?, ?>> {
  // ...
  public final P getParent() { ... }
  public final Set<C> getChildren() { ... }
}

public class City extends Place<Country, Building> { ... )

但在实践中,您可能会发现在这两种情况下简单地返回

Place
更为灵活,并且避免在类型系统中硬编码层次结构的不同级别之间的关系。如果事情发生变化(例如,您在
State
Country
之间引入
City
类型),您必须根据先前的关系更正每个调用站点。


0
投票

测试 S S S S D F

胡 乌伊穆约 阿西斯 AMC 吉诺克斯 D D S


-1
投票

看一下复合模式,也许可以使用一些标记接口。

© www.soinside.com 2019 - 2024. All rights reserved.