I've got A base class Base
and Sorter
and Parser
classes derived from it .
The same thing with BaseResult
with derived SorterResult
and ParserResult
.
Base
has a Result
field of BaseResult
type, BaseResult
has a Log
field.
The reason why I've used a Base
class, is because both of Parser
and Sorter
must write a Log.
Here's my code:
Public MustInherit Class Base
Public Result As BaseResult
Event LogChanged()
Protected Sub AddLogLine(ByVal _logString As String)
If Not String.IsNullOrWhiteSpace(_logString) Then Result.Log.Add(_logString)
RaiseEvent LogChanged()
End Sub
End Class
Public Class Sorter
Inherits Base
Public Shadows Result As SorterResult
Sub New()
Result = New SorterResult With {.Log = New List(Of String)}
End Sub
Sub Go()
AddLogLine("Sorter started")
End Sub
End Class
Public Class Parser
Inherits Base
Public Shadows Result As ParserResult
Sub New()
Result = New ParserResult With {.Log = New List(Of String)}
End Sub
Sub Go()
AddLogLine("Sorter started")
End Sub
End Class
Public MustInherit Class BaseResult
Public Log As List(Of String)
End Class
Public Class SorterResult
Inherits BaseResult
'//SorterResult fields
End Class
Public Class ParserResult
Inherits BaseResult
'//ParsedResult fields
End Class
The issue here is that compiler sais(on pic below):
"variable 'Result' conflicts with variable 'Result' in the base class 'Base' and should be declared 'Shadows'." When I used Shadows keyword, warning disappeared, but I get a null reference exception on this line, because Result
field is Nothing
:
If Not String.IsNullOrWhiteSpace(_logString) Then Result.Log.Add(_logString)
I can't assign a value to a Result
variable in Base
class constructor, because It must be of type SorterResult
in Sorter
, and ParserResult
in Parser
. What is the regular pattern here? Sorry my bad english.
Use generics
Public MustInherit Class Base(Of TResult As BaseResult)
Public Result As TResult
Event LogChanged()
Protected Sub AddLogLine(ByVal _logString As String)
If Not String.IsNullOrEmpty(_logString) Then Result.Log.Add(_logString)
RaiseEvent LogChanged()
End Sub
Public MustOverride Sub Go()
End Class
Public Class Sorter
Inherits Base(Of SorterResult)
Sub New()
Result = New SorterResult With {.Log = New List(Of String)}
End Sub
Public Overrides Sub Go()
AddLogLine("Sorter started")
End Sub
End Class
Public Class Parser
Inherits Base(Of ParserResult)
Sub New()
Result = New ParserResult With {.Log = New List(Of String)}
End Sub
Public Overrides Sub Go()
AddLogLine("Sorter started")
End Sub
End Class
However, this is not a "beautiful" inheritance hierarchy. Inheritance should formulate relations like "a student is a person" where student
derives from person
. What do sorters and parsers have in common? Are they a Base
? Are they loggers? Are they commands (as suggests the Go
method)? Is inheritance required here? Wouldn’t it be more appropriate to use aggregation? I would declare a completely independent logger class and inject it into classes. This allows you to be more flexible, as it enables you to inject different types of loggers.
Public MustInherit Class Logger
Public Event LogChanged()
Public MustOverride Sub AddLogLine(ByVal message As String)
Protected Sub OnLogChanged()
RaiseEvent LogChanged()
End Sub
End Class
Public Class TextFileLogger
Inherits Logger
Public Overrides Sub AddLogLine(ByVal message As String)
If Not String.IsNullOrEmpty(message) Then
'TODO: Write message to log file
OnLogChanged()
End If
End Sub
End Class
You can inject it like this:
Public Class SomeConsumerClass
Private _logger As Logger
Sub New(ByVal logger As Logger)
_logger = logger
End Sub
Public Sub DoSomething()
_logger.AddLogLine("Did something!")
End Sub
End Class
Use like this:
Dim obj As New SomeConsumerClass(New TextFileLogger())
obj.DoSomething()
If you have another kind of logger (XmlFileLogger, StringListLogger, DatabaseLogger...) it is now easy to use it without having to change all the classes using it.
Maybe you should even have only one global logger:
Dim globalLogger As New TextFileLogger()
Dim sorter As New Sorter(globalLogger)
Dim parser As New Parser(globalLogger)