February 13, 2018

Example of the Visitor Pattern


A simple but non-contrived example of the Visitor pattern. Here are the main classes.

// Interface for the visiting system permit populator
public interface IPopulatorVisitor
{
    void PopulateVisit(ISet<int> permitSystemsSet);
}

public interface IPermitSystems
{
    void AcceptPopulator(IPopulatorVisitor populatorVisitor);

    bool PermitRequired(int systemId);
}

// This is the Visitor target
// It stores a set of systems that require a permit for entry
public class PermitSystems : IPermitSystems
{
    HashSet<int> _permitRequiredSystemIds = new HashSet<int>();

    // Accept Visitors here
    public void AcceptPopulator(IPopulatorVisitor populatorVisitor)
    {
        populatorVisitor.PopulateVisit(_permitRequiredSystemIds);
    }

    public bool PermitRequired(int systemId)
    {
        bool res = _permitRequiredSystemIds.Contains(systemId);
        return res;
    }
}

The Visitor class, this has removed the responsibility for deserialising the permit data from the the PermitSystems class. In this case the data is stored in 'JSonl' form, but it could be stored in other formats and a different visitor would be provided

public class PermitSystemsJsonlDeserialiserVisitor 
    : IPopulatorVisitor
{
    FileInfo _jsonlFilePath;

    public void Initialise(string jsonlFilePath)
    {
        _jsonlFilePath = new FileInfo(jsonlFilePath);
    }

    public void PopulateVisit(ISet<int> permitSystemsSet)
    {
        List permitReqdSystems;
        if (_jsonlFilePath.TryLoadFromJson(out permitReqdSystems))
        {
            if (permitReqdSystems != null)
            {
                PopulateImpl(permitSystemsSet, permitReqdSystems);
            }
        }
    }

    private static void PopulateImpl(ISet<int> permitSystemsSet, 
        List permitReqdSystems)
    {
        foreach (var sys in permitReqdSystems)
        {
            Trace.WriteLine(" Permit required for id=" + sys.id + " name=" + sys.name +
                            " permitRequired=" + sys.permitRequired);
            permitSystemsSet.Add(sys.id);
        }
    }
}
Some sample code to bring it all together
[Test]
public void PermitSystemsExperiment()
{
    IPermitSystems permitSystems = new PermitSystems();
    PermitSystemsJsonlDeserialiserVisitor jdv = new PermitSystemsJsonlDeserialiserVisitor();
    jdv.Initialise(TestFilePaths.PermitRequiredSystemsJSonFilePath);
    permitSystems.AcceptPopulator(jdv);

    Assert.That(true == permitSystems.PermitRequired(19054));
    Assert.That(false == permitSystems.PermitRequired(26));
}