Prime Programming Proficiency, Part 3: Lines-of-code Counter, Page 2
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.