PmMda implements the visitor pattern to traverse a graph of data objects. This pattern allows to visit all data objects within a DOG (data object graph). Each data object is just visited once even if a data object is referenced more than once or if the DOG contains cycles.
The visitor is represented through the IDataObjectVisitor
interface. The
vistor specifies whether to visit unloaded items of paged collections, the current deep
and whether a data object was already
visited.
The DataObjectVisitorFunctor
class is one default implementation of this visitor.
This class allows to specify a functor that is executed for every visited data object. A
functor must implement the IDataObjectFunctor
interface which defines the
Execute(IDataObject)
method. This method is called once for every
data object that is visited by the
visitor. Even if the data object is
referenced multiple times in the DOG, the Execute
method is called only once.
See the class diagram below for an overview of visitor and functor interfaces and classes.
This exapmle implements a simple collect funtor that can collect all visited data object in a list.
public class MyCollectFunctor : IDataObjectFunctor { private ArrayList m_collectedObjects; public MyCollectFunctor() { m_collectedObjects = new ArrayList(); } public IDataObject[] CollectedObjects { get { return (IDataObject[]) m_collectedObjects.ToArray(typeof(IDataObject)); } } public void Execute(IDataObject dataObject) { m_collectedObjects.Add(dataObject); } }
IDataObject myRootDataObject = Locator.DataObjectManager.DataObjectHandler.Retrieve(/*...*/); MyCollectFunctor functor = new MyCollectFunctor(); DataObjectVisitorFunctor visitor = new DataObjectVisitorFunctor(functor, true /*collect unloaded items too*/); myRootDataObject.Accept(visitor); IDataObject[] allObjectsReferencedByRoot = visitor.CollectedObjects;
The implemented visitor is neighter a depth first nor a breadth first algorithm. It is
important to visit the data objects
in a fixed order to support NHibernate. The pmMDA framework uses the visitor
pattern to collect all data objects
within a DOG. The collected objects are stored using the NHibernate framework for which
it is important that the row which is referenced by a foreign key is saved before
the owner of the foreign key. Therefore the single properties must be saved before
the indexed property.
To support the visitor pattern, every
data object must implement the
void Accept(IDataObjectVisitor visitor)
method. Within that method the
data object must first call the
Accept
method on all
data objects that are referenced by a
single property. Then the Visit
method of the specified visitor is called
(visitor.Visit(this)
) before all
data objects that are referenced by an
indexed property are accepted.
Example:
public class MyDataObject : IDataObject { // ... void Accept(IDataObjectVisitor visitor) { if (!visitor.Visited(this) { visitor.Depth++; // visit all single properties. m_property1.Accept(visitor); m_property2.Accept(visitor); //... // Visit the current data object visitor.Visit(this); // visit all items of the indexed properties. foreach (IDataObject obj in m_indexedProperty1) { obj.Accept(visitor); } foreach (IDataObject obj in m_indexedProperty2) { obj.Accept(visitor); } // ... visitor.Depth--; } } }