Вопрос Java по проверке типа во время выполнения в реализованном методе - PullRequest
0 голосов
/ 16 декабря 2018

Я проектирую некоторые 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!");
        }
    }
}

Мой вопрос о том, как я имею дело с методом addNodes в интерфейсе Node винтерфейс TreeNode.Метод addNodes должен быть в интерфейсе Node, потому что я хочу позволить людям писать код, который может добавлять узлы в графы.Однако я также не хочу, чтобы люди добавляли произвольные узлы к узлу дерева (например, добавляли узел графа к узлу дерева).

Чтобы это предотвратить, я проверяю тип узловво время выполнения и выдачи исключения, если тип не правильный.Мне просто интересно, если это лучший способ выполнить то, что я хочу, или есть лучшая практика?

Спасибо за помощь :)

Ответы [ 2 ]

0 голосов
/ 16 декабря 2018

Если я правильно понимаю, вы хотите (вариация) так называемый странно повторяющийся шаблон .Тип Node должен быть параметризован не только типом полезной нагрузки (T), но и типом узлов, с которыми он может использоваться.Итак, вы хотите что-то вроде:

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

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

    @Override
    default List<TreeNode<T>> getNeighbors() {
        return getChildren();
    }

    @Override
    default void addNodes(List<TreeNode<T>> nodes) {
        addChildren(nodes);
    }
}

Демо (показывает только компиляцию): https://ideone.com/44qrmX

0 голосов
/ 16 декабря 2018

На мой взгляд, Node - это контейнер для некоторых данных.Tree и Graph - это два способа поддерживать отношения между узлами.Поэтому, возможно, следует определить три класса:

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; }
}

EDIT : если вы хотите иметь общие алгоритмы обхода, вы можете поместить их в отдельные классы и использовать в 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) {
        ...
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...