我正在尝试在java中实现Graph数据结构。 以下是课程:
interface Graph<N,E> {
addNode(N nodeData);
createEdge(N src, N dest, E edgeData);
//and many more api methods
}
class GenericGraph<N,E> implements Graph<N,E> {
Set<Node<N,E>> vertices;
static class Node<N,E> {
private N node;
private Set<Edge<N, E>> adjacencyList;
// getters and setters
}
static class Edge<N, E> {
private E edgeData;
private Node<N, E> src;
private Node<N, E> dest;
// getters and setters
}
//******** API methods implementation*********
Node<N, E> findNode(N nodeData) {
Node<N, E> node = new Node<>(nodeData);
if (vertices.contains(node)) {
for (Node<N, E> tempNode : vertices) {
if (Objects.equals(tempNode, node)) {
node = tempNode;
return node;
}
}
}
return null;
}
Node<N, E> createNode(N nodeData) {
Node<N, E> node = findNode(nodeData);
if (node == null) {
node = new Node<>(nodeData);
vertices.add(node);
}
return node;
}
@Override
public void addNode(N nodeData) {
createNode(nodeData);
}
// other api methods
}
这里我创建了两个嵌套类:Node和Edge
一个图形对象可以有许多节点。
一个节点对象可以有一个相邻顶点的列表。
相邻顶点被视为Edge,其中包含
->src node
->dest node
->edge relation bw the two
GenericGraph api方法使用Node和Edge类来实现。
直到现在一切正常。
现在我想创建一些其他类比GenericGraph更多的功能,比如BfsGraph,DfsGraph等。
BFS算法需要为其节点提供3个额外参数:
->color
->parent
->distance
我正在考虑像这样创建BfsGraph:
class BfsGraph<N,E> extends GenericGraph<N,E> {
//access public,protected and default methods of GenericGraph
private enum NodeColor {
WHITE, GRAY, BLACK;
}
static class BfsNode<N,E> extends GenericGraph.Node<N,E> {
private NodeColor color = NodeColor.WHITE;
private Integer distance = Integer.MAX_VALUE;
private Node<N, E> parent;
BfsNode(N node) {
super(node);
}
}
}
这个设计的问题是,我必须从GenericGraph复制每个方法并根据自己的需要在BfsGraph中重新实现它(Node将更改为BfsNode)。
将来如果我想进行其他实现,那么我再次需要复制和修改所有方法。
必须重复使用GenericGraph编写的算法/逻辑,而不是重写。
请为我推荐一个新的解决方案或任何修改。
答案 0 :(得分:1)
从您的描述中,听起来子类需要能够控制两件事:
Node
实例必须是Node
子类型的实例。
protected
中创建一个名为GenericGraph
的{{1}}方法来处理,该方法只是实例化createNode
。然后Node
可以在需要GenericGraph
实例时调用该方法;和子类可以覆盖该方法,以提供Node
的正确子类型。Node
方法,但除了创建节点之外还有其他逻辑。您应该将该方法重命名为能够捕获其全部用途的方法。需要将createNode
方法声明为返回findNode
的相应子类型。
这可以通过让子类覆盖Node
来处理,但是覆盖只需委托给超类并执行适当的强制转换,如下所示:
findNode
BsfNode<N, E> findNode(N nodeData) {
return (BsfNode<N, E>) super.findNode(nodeData);
}
实际上把它的节点类型作为一个类型参数,这样就可以通过泛型的魔力来处理,而不是要求显式覆盖。但这听起来并不像你认为这种方法值得的那样。