Navigator - examples

Printer-friendly versionPrinter-friendly version
How to use the Navigator framework

Here you can find some simplified examples, how to use the Navigator framework.

 

Using the Navigator framework to apply behavior to an object model is normally as simple as to type something like

new FooNavigator().navigate(bar);

where "Foo" symbolizes a term for any behavior and "bar" represents an object model to apply that behavior to. More generalized we can write

new BehaviorialNavigator().navigate(objectGraph);

In all cases the object(s) passed to the Navigator must be navigable, that is, they implement the Navigable interface. This applies also when passing anything iterable (like a Collection) to the Navigator (but not for the Iterable itself):

Set<Navigable> navigables = ...
new BehaviorialNavigator().navigate(navigables);

In all examples above the Navigator will navigate the given object(s), that is, the Navigator traverses the respective object graph(s) in a manner determined by the Navigator itself. The Navigation is controlled by the Navigator in terms of sequence (can be sorted or filtered), omitting individual nodes or entire branches of a given graph, navigating back all the way or jumping back to certain nodes, etc.

This is in contrast to implementations of the the Visitor pattern where the given model determines the traversal and without any flexibility. Nevertheless, in a basic use the Navigator framework feels similar as a Visitor implementation does and can be used at least in all cases where we would otherwise implement a Visitor, but thanks to the great mightiness of the Navigators in much more cases as well.

Let's see how to implement Navigators and Navigables specifically for our own application or use cases. For the purposes of these examples we assume our application has a domain model with AbstractParent, AbstractChild, ConcreteParent1, ConcreteParent2, ConcreteChild1, ConcreteChild2.

First we should implement an abstract Navigator which extends the NavigatorBase with one "access"-method for each type in our domain model:

public abstract class AbstractParentNavigator extends NavigatorBase {
    
    public void access(Navigable navigable) {}
    
    public void access(AbstractParent navigable) {
        access((Navigable) navigable);
    }
    
    public void access(AbstractChild navigable) {
        access((Navigable) navigable);
    }
    
    public void access(ConcreteParent1 navigable) {
        access((AbstractParent) navigable);
    }
    
    public void access(ConcreteParent2 navigable) {
        access((AbstractParent) navigable);
    }
    
    public void access(ConcreteChild1 navigable) {
        access((AbstractChild) navigable);
    }
    
    public void access(ConcreteChild2 navigable) {
        access((AbstractChild) navigable);
    }
    
}

As you can see, the abstract Navigator reflects the type hierarchy of our domain model up to the Navigable interface itself. It does not compile yet because the model does not implement the Navigable interface yet. That's what we will do next.

Note: In case the abstract Navigator becomes too huge or the domain model should be segregated for other reasons, we can implement as many divisions of abstract Navigators as we want, but always remember in Java we do not have multiple inheritance.

 

 

Seiten