Prime Programming Proficiency, Part 3: Lines-of-code Counter

Implementing the IVisitor Interface

The Visitor pattern can be implemented using abstract classes or interfaces. I chose interfaces. The basic idea is that you define an interface with methods named Visit. For each kind of thing you want to Visit, you define an overloaded Visit method. For example, I want to the Visit SolutionElement, ItemElement, and ProjectElement types; hence, I declare a Visit method for each of these types in IVisitor. In addition, the Visitor is visiting each of these types and grabbing information from them. It will be up to the Visitor to store that information. In our example, we store project, item, and line counts. Therefore, our visitors also will need to collect and make accessible this information.

Listing 3 shows the definition of IVisitor and the implementation of an IVisitor, the Visitor class.

Listing 3: The IVisitor interface and Visitor class.

' IVisitor.vb
Imports EnvDTE
Imports System.Diagnostics
Public Interface IVisitor
Sub Visit(ByVal element As SolutionElement)
Sub Visit(ByVal element As ItemElement)
Sub Visit(ByVal element As ProjectElement)
Property ProjectCount() As Long
Property ItemCount() As Long
Property LineCount() As Long
End Interface
' Visitor.vb
Imports EnvDTE
Imports System.Diagnostics
Public Class Visitor
Implements IVisitor
Private FProjectCount As Long = 0
Private FItemCount As Long = 0
Private FLineCount As Long = 0
Public Property ProjectCount() As Long Implements _
IVisitor.ProjectCount
Get
Return FProjectCount
End Get
Set(ByVal Value As Long)
FProjectCount = Value
End Set
End Property
Public Property ItemCount() As Long Implements _
IVisitor.ItemCount
Get
Return FItemCount
End Get
Set(ByVal Value As Long)
FItemCount = Value
End Set
End Property
Public Property LineCount() As Long Implements _
IVisitor.LineCount
Get
Return FLineCount
End Get
Set(ByVal Value As Long)
FLineCount = Value
End Set
End Property
Public Sub VisitProject(ByVal element As ProjectElement) _
Implements IVisitor.Visit
element.Iterate()
End Sub
Public Sub VisitProjectItem(ByVal element As ItemElement) _
Implements IVisitor.Visit
element.Iterate()
End Sub
Public Sub VisitProjects(ByVal element As SolutionElement) _
Implements IVisitor.Visit
element.Iterate()
End Sub
End Class

I hope you appreciate just how simple the code is. Individual pieces of code should be pretty simple. This supports the idea of divid et imperum, or divide and conquer. To divide and conquer a problem means to subdivide it into smaller, easier-to-implement pieces.

As you will see shortly, each of the prefixSolution classes implement an Iterate method that supports traversing that node's solution and project directory-based file system. For example, a ProjectItem might be a folder that contains other folders or files that require traversing that ProjectItem's elements.