关于实现方法中运行时类型检查的Java问题

时间:2018-12-15 22:11:40

标签: java oop design-patterns

我正在设计一些Java对象来表示图形和树。对于我的用例,我将同时使用这两种数据类型,但我也希望图形算法能够在我的树上工作。

import java.util.List;

public interface Node<T> {
    T getValue();
    List<? extends Node<T>> getNeighbors();
    void addNodes(List<? extends Node<T>> nodes);
}

public interface TreeNode<T> extends Node<T> {
    List<? extends TreeNode<T>> getChildren();
    void addChildren(List<? extends TreeNode<T>> treeNodes);

    @Override
    default List<? extends Node<T>> getNeighbors() {
        return getChildren();
    }

    @Override
    default void addNodes(List<? extends Node<T>> nodes) {
        if(nodes.getClass().isInstance(getChildren().getClass())) {
            addChildren((List<? extends TreeNode<T>>) nodes);
        } else {
            throw new RuntimeException("Type error!");
        }
    }
}

我的问题是我如何在TreeNode接口的Node接口中处理addNodes方法。 addNodes方法必须位于Node界面中,因为我希望允许人们编写可将节点添加至图形的代码。但是,我也不希望人们将任意节点添加到树节点(例如,将图节点添加到树节点)。

为了防止这种情况,我在运行时检查节点的类型,如果类型不正确,则会引发异常。我只是想知道这是否是实现我想要的最佳方法,或者是否有更好的做法?

感谢您的帮助:)

2 个答案:

答案 0 :(得分:2)

如果我的理解正确,那么您想要的是所谓的curiously recurring template pattern(有所变化)。 $ cat -n solution.sh 1 #!/bin/bash 2 3 grep -Po '\b(first|third|Any1):\w+' | cut -d: -f2 4 $ cat infile.txt Something(first:test, second:test2, third:test4, fourth:test4, fifth(Field(test:1, test2:test2,...)), Any1:test1, Any2:test3. $ solution.sh < infile.txt test test4 test1 类型不仅需要根据其有效负载类型(T)进行参数化,而且还需要根据其可以使用的节点类型进行参数化。所以你想要类似的东西:

Node

演示(仅显示编辑):https://ideone.com/44qrmX

答案 1 :(得分:0)

我的看法是Node是一些数据的容器。 TreeGraph是维护节点之间关系的两种方法。所以也许应该定义三个类:

import java.util.List;

public class Node<T> {
    private T value;
    public Node(T value) { this.value = value; }
    T getValue() { return value; }
}

public abstract class Tree<T> {
    private Node<T> root;

    public abstract List<? extends Node<T>> getChildren();
    public abstract void addChildren(List<? extends Node<T>> nodes);

    public Tree(Node<T> root) { this.root = root; }
}

public abstract class Graph<T> {
    private Node<T> root;

    public abstract List<? extends Node<T>> getNeighbors();
    public abstract void addNeighbors(List<? extends Node<T>> nodes);

    public Graph(Node<T> root) { this.root = root; }
}

编辑:如果您希望使用共享遍历算法,可以将它们放在单独的类中,并让Tree和Graph使用类似的语义,如下所示:

// common semantics for node containers
public interface NodeContainer<T> {
    List<? extends Node<T>> getRelatedNodes();
}

public abstract class Tree<T> implements NodeContainer<T> {

    ...  // same as above

    @Override
    public List<? extends Node<T>> getRelatedNodes() {
        return getChildren();
    }
}

public class NodeContainerTraversal {

    public void bfs (NodeContainer<?> container) {
        ...
    }
}