在工厂中订阅事件处理程序
Subscribing event handlers in a factory
我正在编写一个需要通过 TCP 套接字接收消息的 VB.Net 应用程序,但我的问题确实与套接字无关。为简单起见,假设我想创建一个 class 来处理来自 Socket class 事件的数据,该事件是我们公司创建的 class 库的一部分。在研究依赖注入时,this article and this one 说不要将 Socket 实例注入到消息处理器的构造函数中,这样处理器就可以订阅事件。相反,我应该给我的处理器一个 public 函数,让组合根创建一个套接字和处理器,并从套接字连接处理程序,以便它调用处理器上的 public 函数。一开始效果很好。
但是现在我遇到了一个需要动态创建和释放套接字的情况。上述技术的问题是套接字、处理器和事件订阅将在应用程序的生命周期内存在。我想我可以使用工厂来创建处理器对象。然后工厂将创建套接字、处理器并订阅事件处理程序。但它只是 returns 客户端的处理器,那么它怎么取消订阅处理程序呢?我不想因为未能取消订阅事件处理程序而导致泄漏。
已更新
以下代码是一个完整的控制台应用程序。希望我在简单性和解释问题之间找到了正确的平衡。
Imports System.Collections.Concurrent
Module Module1
Sub Main()
'Create a connection
Dim ConnectionClient As New ConnectionClient(New MessageConnectionFactory)
'Do some sending and receiving
ConnectionClient.DoSomething()
'Wait so the user can see results
Console.WriteLine("Press any key")
Console.ReadLine()
End Sub
End Module
Public Class DataProducedEventArgs
Inherits EventArgs
Public Property Data As Byte()
End Class
Public Class Socket
Public Event DataProduced As EventHandler(Of DataProducedEventArgs)
'In a real application, the event would fire when we receive data on the socket.
'This provides a way to simulate that.
Public Sub SimulateReceivedData(Data As Byte())
RaiseEvent DataProduced(Me, New DataProducedEventArgs With {.Data = Data})
End Sub
Public Sub Send(Data As String)
Console.WriteLine("Sending over socket: {0}", Data)
End Sub
End Class
Public Class MessageProcessor
Public Sub Consume(Data As Byte())
Console.WriteLine("Received {0} bytes of data", Data.Length)
End Sub
End Class
Public Class MessageSender
Private _socket As Socket
Public Sub New(socket As Socket)
_socket = socket
End Sub
Public Sub Send(Message As String)
_socket.Send(Message)
End Sub
End Class
Public Class MessageConnection
Public Property Processor As MessageProcessor
Public Property Sender As MessageSender
End Class
Public Class ConnectionClient
Private _Factory As MessageConnectionFactory
Private Connections As New ConcurrentQueue(Of MessageConnection)
Public Sub New(factory As MessageConnectionFactory)
_Factory = factory
End Sub
Public Sub DoSomething()
'Get a connection
Dim Connection As MessageConnection = _Factory.Create
'Do something with it
Connection.Sender.Send("Test")
'TODO - I could dispose of it here but that doesn't
'remove the event handlers
End Sub
End Class
Public Class MessageConnectionFactory
Public Function Create() As MessageConnection
'Create the objects
Dim MySocket As New Socket
Dim Connection As New MessageConnection
Connection.Processor = New MessageProcessor
Connection.Sender = New MessageSender(MySocket)
'How could this handler ever get removed?
AddHandler MySocket.DataProduced, Sub(sender, e) Connection.Processor.Consume(e.Data)
'The client only cares about the message connection object, not the socket
Return Connection
End Function
End Class
这对你有用吗?
Public Class ConnectionClient
Private _Factory As MessageConnectionFactory
Public Sub New(factory As MessageConnectionFactory)
_Factory = factory
End Sub
Public Sub DoSomething()
_Factory.Using(Sub(c) c.Sender.Send("Test"))
End Sub
End Class
Public Class MessageConnectionFactory
Public Sub [Using](action As Action(Of MessageConnection))
Dim MySocket As New Socket
Dim Connection As New MessageConnection
Connection.Processor = New MessageProcessor
Connection.Sender = New MessageSender(MySocket)
Dim handler = New EventHandler(Of DataProducedEventArgs)(Sub(sender, e) Connection.Processor.Consume(e.Data))
AddHandler MySocket.DataProduced, handler
action(Connection)
RemoveHandler MySocket.DataProduced, handler
End Sub
End Class
我正在编写一个需要通过 TCP 套接字接收消息的 VB.Net 应用程序,但我的问题确实与套接字无关。为简单起见,假设我想创建一个 class 来处理来自 Socket class 事件的数据,该事件是我们公司创建的 class 库的一部分。在研究依赖注入时,this article and this one 说不要将 Socket 实例注入到消息处理器的构造函数中,这样处理器就可以订阅事件。相反,我应该给我的处理器一个 public 函数,让组合根创建一个套接字和处理器,并从套接字连接处理程序,以便它调用处理器上的 public 函数。一开始效果很好。
但是现在我遇到了一个需要动态创建和释放套接字的情况。上述技术的问题是套接字、处理器和事件订阅将在应用程序的生命周期内存在。我想我可以使用工厂来创建处理器对象。然后工厂将创建套接字、处理器并订阅事件处理程序。但它只是 returns 客户端的处理器,那么它怎么取消订阅处理程序呢?我不想因为未能取消订阅事件处理程序而导致泄漏。
已更新
以下代码是一个完整的控制台应用程序。希望我在简单性和解释问题之间找到了正确的平衡。
Imports System.Collections.Concurrent
Module Module1
Sub Main()
'Create a connection
Dim ConnectionClient As New ConnectionClient(New MessageConnectionFactory)
'Do some sending and receiving
ConnectionClient.DoSomething()
'Wait so the user can see results
Console.WriteLine("Press any key")
Console.ReadLine()
End Sub
End Module
Public Class DataProducedEventArgs
Inherits EventArgs
Public Property Data As Byte()
End Class
Public Class Socket
Public Event DataProduced As EventHandler(Of DataProducedEventArgs)
'In a real application, the event would fire when we receive data on the socket.
'This provides a way to simulate that.
Public Sub SimulateReceivedData(Data As Byte())
RaiseEvent DataProduced(Me, New DataProducedEventArgs With {.Data = Data})
End Sub
Public Sub Send(Data As String)
Console.WriteLine("Sending over socket: {0}", Data)
End Sub
End Class
Public Class MessageProcessor
Public Sub Consume(Data As Byte())
Console.WriteLine("Received {0} bytes of data", Data.Length)
End Sub
End Class
Public Class MessageSender
Private _socket As Socket
Public Sub New(socket As Socket)
_socket = socket
End Sub
Public Sub Send(Message As String)
_socket.Send(Message)
End Sub
End Class
Public Class MessageConnection
Public Property Processor As MessageProcessor
Public Property Sender As MessageSender
End Class
Public Class ConnectionClient
Private _Factory As MessageConnectionFactory
Private Connections As New ConcurrentQueue(Of MessageConnection)
Public Sub New(factory As MessageConnectionFactory)
_Factory = factory
End Sub
Public Sub DoSomething()
'Get a connection
Dim Connection As MessageConnection = _Factory.Create
'Do something with it
Connection.Sender.Send("Test")
'TODO - I could dispose of it here but that doesn't
'remove the event handlers
End Sub
End Class
Public Class MessageConnectionFactory
Public Function Create() As MessageConnection
'Create the objects
Dim MySocket As New Socket
Dim Connection As New MessageConnection
Connection.Processor = New MessageProcessor
Connection.Sender = New MessageSender(MySocket)
'How could this handler ever get removed?
AddHandler MySocket.DataProduced, Sub(sender, e) Connection.Processor.Consume(e.Data)
'The client only cares about the message connection object, not the socket
Return Connection
End Function
End Class
这对你有用吗?
Public Class ConnectionClient
Private _Factory As MessageConnectionFactory
Public Sub New(factory As MessageConnectionFactory)
_Factory = factory
End Sub
Public Sub DoSomething()
_Factory.Using(Sub(c) c.Sender.Send("Test"))
End Sub
End Class
Public Class MessageConnectionFactory
Public Sub [Using](action As Action(Of MessageConnection))
Dim MySocket As New Socket
Dim Connection As New MessageConnection
Connection.Processor = New MessageProcessor
Connection.Sender = New MessageSender(MySocket)
Dim handler = New EventHandler(Of DataProducedEventArgs)(Sub(sender, e) Connection.Processor.Consume(e.Data))
AddHandler MySocket.DataProduced, handler
action(Connection)
RemoveHandler MySocket.DataProduced, handler
End Sub
End Class