Node: may have names and a functional name supplier

Names, where present, must be unique for each parent.

Node:
* String getName()
* void setName(String name)
* boolean isNamed()

NodeItem - replaces all constructor:
* (data)
* (data, name)
* (data, nameSupplier)
* (data, parent)
* (data, nameSupplier, parent)


The name supplier takes a node and generates a string at the time the node
is constructed. The root node has a default name supplier that returns null
which means that the node is considered unnamed. Other nodes may provide
their own name supplier that would be used be new nodes created within
their subtree.
This commit is contained in:
Paul Campbell 2016-05-24 10:59:16 +01:00
parent 36efe5d83a
commit b18020708b
2 changed files with 121 additions and 11 deletions

View file

@ -13,6 +13,20 @@ import java.util.Set;
*/
public interface Node<T> {
/**
* Fetch the name of the node.
*
* @return the name of the node
*/
String getName();
/**
* Sets the explicit name for a node.
*
* @param name the new name
*/
void setName(String name);
/**
* Fetch the data held within the node.
*
@ -112,4 +126,11 @@ public interface Node<T> {
*/
Optional<Node<T>> walkTree(final List<T> path);
/**
* Returns true if the Node has a name.
*
* @return true if the node has a name
*/
boolean isNamed();
}

View file

@ -4,6 +4,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
/**
* Represents a tree of nodes.
@ -16,33 +17,108 @@ public class NodeItem<T> implements Node<T> {
private final T data;
private Node<T> parent;
private final Set<Node<T>> children = new HashSet<>();
private Function<Node<T>, String> nameSupplier;
private Node<T> parent;
private String name;
/**
* Creates a root node.
* Create unnamed root node.
*
* @param data the value of the node
* @param data the data or null
*/
public NodeItem(final T data) {
this(data, null);
this.data = data;
this.nameSupplier = (n) -> null;
}
/**
* Create named root node.
*
* @param data the data or null
* @param name the name
*/
public NodeItem(final T data, final String name) {
this(data);
this.name = name;
}
/**
* Creates root node with a name supplier.
*
* @param data the data or null
* @param nameSupplier the name supplier function
*/
public NodeItem(
final T data, final Function<Node<T>, String> nameSupplier) {
this(data);
this.nameSupplier = nameSupplier;
name = generateName();
}
/**
* Creates a node with a parent.
*
* @param data the value of the node
* @param data the data or null
* @param parent the parent node
*/
public NodeItem(final T data, final Node<T> parent) {
if (data == null) {
throw new NullPointerException("data");
}
this.data = data;
if (parent != null) {
setParent(parent);
this.name = generateName();
}
/**
* Creates a named node with a parent.
*
* @param data the data or null
* @param name the name
* @param parent the parent node
*/
public NodeItem(final T data, final String name, final Node<T> parent) {
this.data = data;
this.name = name;
setParent(parent);
}
/**
* Creates a node with a name supplier and a parent.
*
* @param data the data or null
* @param nameSupplier the name supplier function
* @param parent the parent node
*/
public NodeItem(
final T data, final Function<Node<T>, String> nameSupplier,
final Node<T> parent) {
this(data, nameSupplier);
setParent(parent);
}
private String generateName() {
return getNameSupplier().apply(this);
}
private Function<Node<T>, String> getNameSupplier() {
if (nameSupplier != null) {
return nameSupplier;
}
// no test for parent as root nodes will always have a default name
// supplier
return ((NodeItem<T>) parent).getNameSupplier();
}
@Override
public String getName() {
return name;
}
@Override
public void setName(final String name) {
this.name = name;
}
@Override
@ -98,6 +174,14 @@ public class NodeItem<T> implements Node<T> {
if (this.equals(child) || isChildOf(child)) {
throw new NodeException("Child is an ancestor");
}
if (child.isNamed()) {
final Optional<Node<T>> existingChild = findChildNamed(
child.getName());
if (existingChild.isPresent() && existingChild.get() != child) {
throw new NodeException(
"Node with that name already exists here");
}
}
children.add(child);
if (child.getParent() == null || !child.getParent().equals(this)) {
child.setParent(this);
@ -202,6 +286,11 @@ public class NodeItem<T> implements Node<T> {
public Node<T> createChild(final T child) {
if (child == null) {
throw new NullPointerException("child");
@Override
public boolean isNamed() {
return name != null && name.length() > 0;
}
}
return new NodeItem<>(child, this);
}