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:
parent
36efe5d83a
commit
b18020708b
2 changed files with 121 additions and 11 deletions
|
@ -13,6 +13,20 @@ import java.util.Set;
|
||||||
*/
|
*/
|
||||||
public interface Node<T> {
|
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.
|
* Fetch the data held within the node.
|
||||||
*
|
*
|
||||||
|
@ -112,4 +126,11 @@ public interface Node<T> {
|
||||||
*/
|
*/
|
||||||
Optional<Node<T>> walkTree(final List<T> path);
|
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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a tree of nodes.
|
* Represents a tree of nodes.
|
||||||
|
@ -16,33 +17,108 @@ public class NodeItem<T> implements Node<T> {
|
||||||
|
|
||||||
private final T data;
|
private final T data;
|
||||||
|
|
||||||
private Node<T> parent;
|
|
||||||
|
|
||||||
private final Set<Node<T>> children = new HashSet<>();
|
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) {
|
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.
|
* Creates a node with a parent.
|
||||||
*
|
*
|
||||||
* @param data the value of the node
|
* @param data the data or null
|
||||||
* @param parent the parent node
|
* @param parent the parent node
|
||||||
*/
|
*/
|
||||||
public NodeItem(final T data, final Node<T> parent) {
|
public NodeItem(final T data, final Node<T> parent) {
|
||||||
if (data == null) {
|
|
||||||
throw new NullPointerException("data");
|
|
||||||
}
|
|
||||||
this.data = data;
|
this.data = data;
|
||||||
if (parent != null) {
|
setParent(parent);
|
||||||
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
|
@Override
|
||||||
|
@ -98,6 +174,14 @@ public class NodeItem<T> implements Node<T> {
|
||||||
if (this.equals(child) || isChildOf(child)) {
|
if (this.equals(child) || isChildOf(child)) {
|
||||||
throw new NodeException("Child is an ancestor");
|
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);
|
children.add(child);
|
||||||
if (child.getParent() == null || !child.getParent().equals(this)) {
|
if (child.getParent() == null || !child.getParent().equals(this)) {
|
||||||
child.setParent(this);
|
child.setParent(this);
|
||||||
|
@ -202,6 +286,11 @@ public class NodeItem<T> implements Node<T> {
|
||||||
public Node<T> createChild(final T child) {
|
public Node<T> createChild(final T child) {
|
||||||
if (child == null) {
|
if (child == null) {
|
||||||
throw new NullPointerException("child");
|
throw new NullPointerException("child");
|
||||||
|
@Override
|
||||||
|
public boolean isNamed() {
|
||||||
|
return name != null && name.length() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return new NodeItem<>(child, this);
|
return new NodeItem<>(child, this);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue