0

私は基本クラスBaseSorterそれParserから派生したクラスを持っています。BaseResult派生SorterResultした とと同じことですParserResult。 タイプBaseResultフィールドがあります。フィールドがあります。クラスを使用した理由は、との両方がログを書き込む必要があるためです。これが私のコードです:BaseResultBaseResultLogBaseParserSorter

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

ここでの問題は、コンパイラがサイスであることです(下の写真):ここに画像の説明を入力

「変数 'Result' は、基本クラス 'Base' の変数 'Result' と競合するため、'Shadows' と宣言する必要があります。」 Shadows キーワードを使用すると、警告は消えましたが、ResultフィールドがNothing:

If Not String.IsNullOrWhiteSpace(_logString) Then Result.Log.Add(_logString)

クラスコンストラクターのResult変数に値を割り当てることはできません。これは、 inおよびinの型である必要があるためです。ここで通常のパターンは何ですか?私の悪い英語を申し訳ありません。BaseSorterResultSorterParserResultParser

ここに画像の説明を入力

4

1 に答える 1

2

ジェネリックを使用する

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

ただし、これは「美しい」継承階層ではありません。student継承は、から派生する「学生は人である」のような関係を定式化する必要がありますperson。ソーターとパーサーの共通点は何ですか? 彼らはBaseですか?彼らはロガーですか?それらはコマンドですか(Goメソッドが示唆するように)?ここで継承が必要ですか?集計を使用する方が適切ではないでしょうか? 完全に独立したロガー クラスを宣言し、それをクラスに挿入します。これにより、さまざまなタイプのロガーを挿入できるため、より柔軟に対応できます。

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

次のように注入できます。

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

次のように使用します。

Dim obj As New SomeConsumerClass(New TextFileLogger())
obj.DoSomething()

別の種類のロガー (XmlFileLogger、StringListLogger、DatabaseLogger...) がある場合、それを使用するすべてのクラスを変更する必要なく、簡単に使用できるようになりました。

おそらく、グローバル ロガーは 1 つだけにする必要があります。

Dim globalLogger As New TextFileLogger()
Dim sorter As New Sorter(globalLogger)
Dim parser As New Parser(globalLogger)
于 2014-11-09T18:20:14.503 に答える