创建Java子类的层次结构

创建Java子类的层次结构,java,abstract,Java,Abstract,我试图在java中建立一个位置层次结构。一个地方可以大也可以小,较大的地方包括较小的子位置。所以,一个世界包含国家,国家包含城市,等等,直到建筑物和房间 我创建了一个名为Place的抽象类,它是所有这些类型的父类。每个位置都包含子位置图、父位置图和获取父位置(也称为邻居)的能力 我遇到的主要问题是,父类的子位置应该是类的实例,但是没有办法用java来指定这一点 我考虑过对所有类型进行硬编码,这样City的getParent会返回一个国家,getSublocations会返回一个建筑图,但这会在更

我试图在java中建立一个位置层次结构。一个地方可以大也可以小,较大的地方包括较小的子位置。所以,一个世界包含国家,国家包含城市,等等,直到建筑物和房间

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

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

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

编辑:

谢谢你的回答。这就是我目前所拥有的。这并不完美,但也不太糟糕。我必须复制的唯一代码是getNeights()的实现。它过去直接在抽象类(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;
        }
    }
}
import java.util.HashSet;
公共抽象类场所{
//世界、地区、城市、建筑物、房间
公共枚举方向{
东、东北、北、西北、西、西南、南、东南、无效;
从int(int i)开始的公共静态方向{
开关(一){
案例0:返回东部;
案例1:返回东北;
案例2:返回北方;
案例3:返回西北;
案例4:返回西部;
案例5:返回西南;
案例6:返回南方;
案例7:返回东南部;
默认:返回无效;
}
}
公共静态方向从角度(双角度){
从int((int)(角度+22.5)/45)返回;
}
}
受保护的最终整数锁定=整数最大值;
受保护的整数x,y;//经度和纬度
公共抽象字符串getName();
公共抽象图getSublocations();
公共摘要T getParent();
公共抽象HashSet getneights();
公共最终方向getDirection(地点其他地点){
if(otherPlace==null){
返回方向无效;
}else if(this.getClass()==otherPlace.getClass()){
返回方向。从角度(数学atan2(otherPlace.y-y,otherPlace.x-x));
}否则{
返回方向无效;
}
}
}

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

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;
    }
}
公共接口场所{
//如果需要,Place可以是一个抽象类。
//将其抽象可能会导致一些问题,因为它可能会使您使用泛型
//我推荐一个接口

列表假设每种类型都直接从
位置扩展(而不是像
城市扩展国家,这是错误的),您应该能够用泛型限制您的样板文件,例如:

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> { ... )
public class Place>{
// ...
公共最终P getParent(){…}
公共最终集getChildren(){…}
}
公共类城市扩展位置{…)

然而,在实践中,您可能会发现在这两种情况下更灵活的做法是简单地返回
位置
,并避免在类型系统中硬编码层次结构不同级别之间的关系。如果情况发生变化(例如,在
国家
城市
之间引入
类型)您必须根据之前的关系更正每个呼叫站点。

查看组合模式,并可能使用一些标记接口。

国家/地区是否可以包含非城市位置?即,您是否尝试根据类型筛选兄弟位置,或者您是否尝试在添加时将可能的类型限制在某个级别?是否可以你放了一些代码摘录?这可能有助于我们了解你在寻找什么注意,在现实世界中,这些关系中的许多都不是严格的等级关系。有一些城市在技术上不在任何国家或跨越多个州/国家,仅举一个例子。对于简单的任务,显然等级关系就足够了,但just fair警告它可能会反过来咬你:)听起来你在尝试使用继承(IS-A),而你应该使用组合(HAS-A).World有国家对象,但国家不是世界。国家有城市,但城市不是国家。@azurefrog每层场所只能包含较低层的场所。因此,城市只包含建筑。主要需要的功能是,当getParent()、getSublocations()时,任何场所都会返回指定类型的场所,并调用getNeights()。