创建Java子类的层次结构

时间:2017-10-11 20:14:35

标签: java abstract

我正在尝试在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;
        }
    }
}

3 个答案:

答案 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会更灵活,并避免在类型系统中硬编码层次结构的不同级别之间的关系。如果事情发生变化(例如,您在StateCountry之间引入了City类型),则必须更正依赖于先前关系的每个呼叫网站。

答案 2 :(得分:-1)

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