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.
Implementing hosts
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
