【发布时间】:2020-07-28 07:46:19
【问题描述】:
我对泛型继承有些问题。下面是依赖树:
public class Attributes {
}
public abstract class Feature<T extends Attributes> {
private T attributes;
public T getAttributes() {
return attributes;
}
public void setAttributes(T attributes) {
this.attributes = attributes;
}
}
public abstract class AbstractFeatureRepository<T extends Feature<? extends Attributes>> {
public abstract String getType();
public abstract boolean create(T feature);
}
我有这些功能存储库的实现,如下所示:
public class NodeAttributes extends Attributes {
private String startPoint;
public String getStartPoint() {
return startPoint;
}
public void setStartPoint(String startPoint) {
this.startPoint = startPoint;
}
}
public class Node extends Feature<NodeAttributes> {
}
public class NodeRepository extends AbstractFeatureRepository<Node> {
public String getType() {
return "Node";
}
public boolean create(Node node) {
return true;
}
}
public class LinkAttributes extends Attributes {
private String uri;
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
}
public class Link extends Feature<LinkAttributes> {
}
public class LinkRepository extends AbstractFeatureRepository<Link> {
public String getType() {
return "Link";
}
public boolean create(Link link) {
return true;
}
}
我通过构造函数将这些带有 Spring 的存储库注入到控制器(但在本例中,为了简单起见,我在构造函数中手动创建):
public class Controller {
private final Map<String, AbstractFeatureRepository<? extends Feature>> featureRepositories;
public Controller() {
this.featureRepositories = Arrays.asList(new NodeRepository(), new LinkRepository()).stream()
.collect(Collectors.toMap(AbstractFeatureRepository::getType, Function.identity()));
}
public Node createNode() {
Node newNode = new Node();
newNode.getAttributes().setStartPoint("Berlin");
createFeature("Node", newNode);
return newNode;
}
public Link createLink() {
Link newLink = new Link();
newLink.getAttributes().setUri("/home/local");
createFeature("Link", newLink);
return newLink;
}
private void createFeature(String type, Feature<? extends Attributes> feature) {
featureRepositories.get(type).create(feature);
}
}
一切都很好,直到我想在通用“createFeature”中调用“create”方法,但出现编译错误
AbstractFeatureRepository
不适用于参数 (Feature )
我做错了什么?这是因为我可能会传递某种其他类型的“功能”而不是特定的“存储库”可以使用吗?那么我应该如何在 Controller 中更改我的地图存储库,以便编译器不会抱怨?我虽然应该操作精确的类作为 map 的键,但不知道如何使所有这些工作。有什么建议吗?
谢谢。
更新 1。我将地图更改为
private final Map<Class<?>, AbstractFeatureRepository<? extends Feature>> featureRepositories;
更改了 AbstractFeatureRepository,使其现在看起来像这样:
public abstract class AbstractFeatureRepository<T extends Feature> {
public abstract Class<T> getClazz();
public abstract boolean create(T feature);
}
并更改了控制器中的方法:
public Link createLink() {
Link newLink = new Link();
createFeature(Link.class, newLink);
return newLink;
}
private <T extends Feature> void createFeature(Class<T> class1, T feature) {
AbstractFeatureRepository<? extends Feature> abstractFeatureRepository = featureRepositories.get(feature.getClass());
abstractFeatureRepository.create(abstractFeatureRepository.getClazz().cast(feature));
}
它仍然不允许我这样做。
【问题讨论】:
-
如果你知道,通过构造,
featureRepositories.get("Node")只能是NodeRepository,显式转换。事实上,无论如何,这将是一个检查型强制转换,所以如果不是,它会立即失败。 -
我的第一个建议是摆脱这种过度设计。看起来您刚刚了解了继承和泛型,并且迫不及待地将它们放在不应该出现的地方。至于实际问题
get("Node")不是类型安全的,get(Node.class)会是,因为Class是通用的。但同样,我认为这是一个巨大的设计问题,泛型问题只是一个次要情节。 -
你能给我们提供你的 AbstractRepository 类吗?也许问题就在那里。
-
@AndriyKucher 尽管 Kayaman 对过度工程发表了评论,但您可能会发现“类型安全的异构容器”会有所帮助。 Effective Java 中有描述;我相信您可以在网络上的其他地方找到它。
-
我的评论也不是刻薄的意思。对于这类问题,我只是经常有似曾相识的感觉。