[.Net Concept]適時採用事件動態繫結來替代用If判斷作功能的啟用

對於程式功能的啟用,我想多半一開始大家接觸到的寫法就是用個Flag去判斷功能是否啟用,如果啟用就做某些動作,這樣的程式多半會在主要的程式邏輯中加入If判斷,這樣的寫法雖然在Flag有設的狀態才會執行主要功能,但若Flag未設定,該If判斷多少也都會對其效能造成影響,而且會讓程式的邏輯與新功能的程式混在一起,變得不易理解。因此這邊記錄一下另一種寫法,純粹是個人的小小經驗,小小體會。

這邊簡單的來看個例子:

Class Executor

Private _enableLogData As Boolean
Public Property EnableLogData() As Boolean
Get
Return _enableLogData
End Get
Set(ByVal value As Boolean)
_enableLogData = value
End Set
End Property

Event Executing As EventHandler
Event Executed As EventHandler

Protected Sub OnExecuting(ByVal e As EventArgs)
RaiseEvent Executing(Me, e)
End Sub

Protected Sub OnExecuted(ByVal e As EventArgs)
RaiseEvent Executed(Me, e)
End Sub

Sub GoExecute()
For i As Integer = 1 To 100000000
OnExecuting(New EventArgs)
‘運行動作,這邊為了看出差異,故不做動作
If EnableLogData Then
‘紀錄動作,這邊為了看出差異,故不做動作
End If
OnExecuted(New EventArgs)
Next
End Sub
End Class


這樣的程式若用下面程式去做測試

    Sub Main()
Dim executor As New Executor
Dim sw As Stopwatch = Stopwatch.StartNew
executor.GoExecute()
Console.WriteLine(sw.ElapsedMilliseconds.ToString)

executor.EnableLogData = True
sw.Reset()
sw.Start()
executor.GoExecute()
Console.WriteLine(sw.ElapsedMilliseconds.ToString)
End Sub

輸出的結果如下

image

以這個例子來看,若換個想法改用事件動態繫結的方式去做,當啟動功能時才把功能的動作繫上,當關閉功能時把功能的動作給卸下,功能的動作就可以跟主要的邏輯分開,少了不必要的If判斷,同一個事件也可以繫上不同功能的動作。

Class Executor

Private _enableLogData As Boolean
Public Property EnableLogData() As Boolean
Get
Return _enableLogData
End Get
Set(ByVal value As Boolean)
If _enableLogData <> value Then
OnEnableLogDataChanging(New EventArgs)
_enableLogData = value
OnEnableLogDataChanged(New EventArgs)
End If
End Set
End Property

Event EnableLogDataChanging As EventHandler
Event EnableLogDataChanged As EventHandler
Event Executing As EventHandler
Event Executed As EventHandler

Protected Sub OnEnableLogDataChanging(ByVal e As EventArgs)
RaiseEvent EnableLogDataChanging(Me, e)
End Sub

Protected Sub OnEnableLogDataChanged(ByVal e As EventArgs)
RaiseEvent EnableLogDataChanged(Me, e)
End Sub

Protected Sub OnExecuting(ByVal e As EventArgs)
RaiseEvent Executing(Me, e)
End Sub

Protected Sub OnExecuted(ByVal e As EventArgs)
RaiseEvent Executed(Me, e)
End Sub

Sub GoExecute()
For i As Integer = 1 To 100000000
OnExecuting(New EventArgs)
‘運行動作,這邊為了看出差異,故不做動作
OnExecuted(New EventArgs)
Next
End Sub

Private Sub LogData(ByVal sender As Object, ByVal e As System.EventArgs)
‘紀錄動作,這邊為了看出差異,故不做動作
End Sub

Private Sub Executor_EnableLogDataChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.EnableLogDataChanged
RemoveHandler Executed, AddressOf LogData
If EnableLogData Then
AddHandler Executed, AddressOf LogData
End If
End Sub
End Class

image