Расширяемая реализация дерева двойных связей в Java - PullRequest
3 голосов
/ 06 декабря 2011

Я хочу расширить существующую реализацию дерева двойных связей некоторыми дополнительными данными.

Поэтому я мог бы реорганизовать базовую реализацию TreeNode, но я хочу иметь отдельную расширенную реализацию TreeNode, потому что в моем реальном сценарии создание ExtandedTreeNode будет намного дороже, чем построениедо базового TreeNode, а дополнительные данные необходимы только для некоторых вариантов использования.

Рудиментный код

Вот мой первый рудиментарный подход для реализации расширяемого дерева двойных связей в Java:

Базовый интерфейс узла дерева:

interface TreeNode
{
    // tree node getters:

    TreeNode getParent();

    List<? extends TreeNode> getChildren();

    // tree node setters:

    void setParent(TreeNode parentNode);

    void addChild(TreeNode childNode);

    // some basic operations:

    boolean isSelectable();

    // [...]
}

Расширенный интерфейс узла дерева:

interface ExtandedTreeNode extends TreeNode
{
    // narrow types of tree node getters of super-interface:

    @Override
    ExtandedTreeNode getParent();

    @Override
    List<? extends ExtandedTreeNode> getChildren();

    // narrowing types of tree node setters of super-interface is not possible!

    // some additional operations:

    boolean isRemoveable();

    // [...]
}

Реализация базового узла дерева:

class TreeNodeImpl implements TreeNode
{
    private TreeNode parent;

    private List<TreeNode> children = new ArrayList<TreeNode>();

    private boolean isSelectable;

    //
    // implement tree node getters:
    //

    @Override
    public TreeNode getParent()
    {
        return parent;
    }

    @Override
    public List<? extends TreeNode> getChildren()
    {
        return children;
    }

    //
    // implement tree node setters:
    //

    @Override
    public void setParent(TreeNode parent)
    {
        this.parent = parent;
    }

    @Override
    public void addChild(TreeNode childNode)
    {
        children.add(childNode);
    }

    //
    // implement basic operations:
    //

    @Override
    public boolean isSelectable()
    {
        return isSelectable;
    }

    // [...]
}

Расширенное деревореализация узла:

class ExtandedTreeNodeImpl implements ExtandedTreeNode
{
    private ExtandedTreeNode parent;

    private List<ExtandedTreeNode> children = new ArrayList<ExtandedTreeNode>();

    private TreeNode treeNode;

    private boolean isRemoveable;

    public ExtandedTreeNodeImpl()
    {
        treeNode = new TreeNodeImpl();
    }

    //
    // implement tree node getters:
    //

    @Override
    public ExtandedTreeNode getParent()
    {
        return parent;
    }

    @Override
    public List<? extends ExtandedTreeNode> getChildren()
    {
        return children;
    }

    //
    // implement tree node setters:
    //

    @Override
    public void setParent(TreeNode parent)
    {
        this.parent = (ExtandedTreeNode) parent; // <--- How to avoid this type cast!!
    }

    @Override
    public void addChild(TreeNode childNode)
    {
        children.add((ExtandedTreeNode) childNode); // <--- How to avoid this type cast!!
    }

    //
    // implement basic operations by delegating to composite TreeNode:
    //

    public boolean isSelectable()
    {
        return treeNode.isSelectable();
    }

    // [...]

    //
    // implement additional operations:
    //

    @Override
    public boolean isRemoveable()
    {
        return isRemoveable;
    }

    // [...]
}

Вопрос

Для меня иерархия типов отлично подходит для методов, доступных только для чтения и не для узлов дерева, но утечка для сеттеров setParent(..)и addChild(..).В частности, рискованный тип ExtandedTreeNode довольно злой, и я хочу от него избавиться.

Я думал об извлечении методов setParent(..) и addChild(..) к двум другим отдельным интерфейсам, таким как TreeNodeWriteable и ExtandedTreeNodeWriteable, но, возможно, есть и более лучшие дизайнерские решения.

Кто-нибудь знает шаблон проектирования или чертеж, который мог бы решить мою проблему с записывающими сеттер-узлами, специфичными для узлов дерева?

Ответы [ 2 ]

2 голосов
/ 06 декабря 2011

Вы можете использовать дженерики. Определите ваш узел дерева следующим образом:

interface TreeNode<N extends TreeNode> {

    N getParent();

    List<N> getChildren();

    void setParent(N parentNode);

    void addChild(N childNode);

}

Теперь ваш TreeNodeImpl будет выглядеть так: class TreeNodeImpl implements TreeNode<TreeNode>

Хотя ExtendedTreeNodeImpl будет определен следующим образом:

class ExtendedTreeNodeImpl implements ExtendedTreeNode<ExtendedTreeNode>

Параметризованные методы в этих классах будут использовать определенные типы: TreeNode и ExtendedTreeNode, поэтому приведение не требуется.

1 голос
/ 06 декабря 2011

Вы могли бы использовать шаблон самостоятельного ввода.Недостатком является то, что весь ваш код заполнен аргументами типов, которые (в большинстве случаев) вам не нужны.

Пример:

interface TreeNode<S extends Node<S>> { // S is the self type
    void setParent(S parent);
    void addChild(S child);
}
interface ExtendedTreeNode extends Node<ExtendedTreeNode> {}

Редактировать: Блог по темесообщение Стивена Колебурна

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...