我正在尝试在java中设置场所的层次结构。一个地方可以是大的或小的,较大的地方包括较小的地方。因此,一个世界包含国家,国家包含城市,等等到建筑物和房间。
我创建了一个名为Place的抽象类,它是所有这些类型的父类。每个地方都包含一个子位置图,一个父位置,以及获得父级子位置(也就是一个邻居)的能力
我遇到的主要问题是,一个人的父母的子位置应该是一个类的实例,但是没有办法用java来指定它。
我考虑过对所有类型进行硬编码,因此City的getParent返回一个Country,而getSublocations返回一个Building of Graph,但是这会在更改类的功能或添加新类时产生一些问题,并且会引起恐怖代码复制量。有没有其他方法可以解决这个问题?
编辑:
感谢所有答案。这就是我到目前为止所拥有的。它并不完美,但它也不是太糟糕。我必须复制的唯一代码是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;
}
}
}
答案 0 :(得分:1)
我曾经遇到过这个问题几次,当你搞乱这样的事情时,我不建议在这种情况下使用泛型,因为你已经知道每个地方将会返回什么。希望这段代码能有所帮助。
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;
}
}
代码中不应该有太多的复制和粘贴,但我认为这是你最好的选择。
答案 1 :(得分: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
类型),则必须更正依赖于先前关系的每个呼叫网站。
答案 2 :(得分:-1)
看看复合模式,并可能使用一些标记接口。