我正在尝试在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;
}
}
}
我已经遇到过这个问题好几次了,当你搞乱这样的事情时,我不建议在这种情况下使用泛型,因为你已经知道每个 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;
}
}
代码中不应该有太多的复制和粘贴,但我认为这是你最好的选择。
假设每种类型都直接从
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
类型),您必须根据先前的关系更正每个调用站点。
测试 S S S S D F
胡 乌伊穆约 阿西斯 AMC 吉诺克斯 D D S
看一下复合模式,也许可以使用一些标记接口。