Prime Programming Proficiency, Part 3: Lines-of-code Counter, Page 3
Implementing the IHost Interface
A good technique for designing solutions is to state the object and pluck out the nouns and verbs. The nouns will tell you what is acting, what is acted upon, and what the actions are. In our implementation, we simply state that hosts are something that accept visitors. Plucking the nouns and verbs we have host, visitor, something, and accept.
Something is suitable here because all kinds of things play the role of host and visitor. The current confluence in my lungs suggests that I am hosting (albeit unwanted guests) some very small visitors. Your grandmother may play host to your family during the holidays, and when my kids forgot to do laundry for a week while I was on a recent business trip my dryer vent was host to a swallow. Because something and patterns in general are generic, the word something suggests we use an interface. Hosts accept visitors, resulting in the culmination of an interface (IHost) with a method (Accept) that requires an IVisitor (see Listing 4 for an implementation of IHost).
Note: Some implementations of the visitor pattern might use Visitor and Visitable. This has a nice symmetry, but Visitor and Host sound a little better. Precise naming is not important. Clarity is sufficient.
Listing 4: The IHost interface.
Imports EnvDTE Imports System.Diagnostics Public Interface IHost Sub Accept(ByVal visitor As IVisitor) End Interface
Every class that accepts a visitor needs to implement IHost. As mentioned previously, the Host is capable of doing or knowing something about the Visitor's wants and needs. In this example, the visitors want to gather count heuristics from each host.
The extensibility object model was not implemented with the Visitor pattern. Thus to make ProjectItem, Project, and Projects (part of the extensibility object model) work with our pattern, we need to wrap these elements in classes that do work with the Visitor, that do implement IHost. I defined the following three classes for this purpose:
- SolutionElement represents the wrapper for a solution, containing a reference to the extensibility object model's Projects collection.
- ProjectElement represents the wrapper for a Project.
- ItemElement wraps ProjectItem.
Listings 5, 6, and 7 show the implementation of each class, respectively. Each listing is followed by a brief summary showcasing the finer points.
Listing 5: The SolutionElement.
Imports EnvDTE Imports System.Diagnostics Public Class SolutionElement Implements IHost Private FProjects As Projects Private FVisitor As IVisitor Public Sub New(ByVal projects As Projects) FProjects = projects End Sub Public ReadOnly Property Projects() As Projects Get Return FProjects End Get End Property Public Sub Accept(ByVal visitor As IVisitor) _ Implements IHost.Accept FVisitor = visitor visitor.Visit(Me) End Sub Public Sub Iterate() Output.Clear() Output.WriteLine(DTE.Solution.FullName) Dim project As Project Dim projectElement As ProjectElement = New ProjectElement For Each project In FProjects projectElement.CurrentProject = project projectElement.Accept(FVisitor) Next End Sub End Class