在 VB.NET 中实现观察者模式






2.94/5 (15投票s)
2004 年 1 月 2 日
3分钟阅读

93659

544
本文展示了一种在 VB.NET 中实现观察者模式的简单方法
解开观察者模式的神秘面纱
当您需要同时以几种不同的形式呈现数据时,观察者模式非常有用。 观察者旨在为您提供一种定义对象之间一对多依赖关系的方法,以便当一个对象的状态发生变化时,其所有依赖项都会被自动通知和更新。 包含数据的对象与显示数据的对象分离,而显示对象会观察该数据中的更改。
基本上有两种不同类型的对象:主题和观察者。 主题对应于您要跟踪其状态的数据对象。 观察者是关注主题数据更改的对象。 要设置该模式,主题类实现一种用于注册观察者以及将它们附加和分离到集合对象的方法。
您还需要一个 Notify(...)
方法,以便在数据发生更改时通知所有已注册的观察者。 对于观察者,您定义一个自定义的抽象 Observer
类以向客户端提供统一的接口,并对实现细节进行子类化。
基本实现
首先,我们定义一个名为 Observer
的公共接口
Public Interface Observer
Sub Update(ByVal subj As Object)
End Interface
我们所有的观察者(即对数据更改感兴趣的对象)都必须实现此接口。
然后我们定义一个抽象的(在 VB.NET 中为 MustInherit
)类,名为 Subject
。 这是我们将要观察其状态的所有对象的基类。
Public MustInherit Class Subject
一个我们要存储观察者的集合。
Private _observers As New ArrayList()
用于添加和删除观察者的方法
Public Sub AddObserver(ByRef ob As Observer)
_observers.Add(ob)
End Sub
Public Sub RemoveObserver(ByRef ob As Observer)
_observers.Remove(ob)
End Sub
最后,一个公共方法将通知我们所有的观察者,主题的状态已经改变。
Public Sub Notify()
Dim ob As Observer
For Each ob In _observers
ob.Update(Me)
Next
End Sub
End Class
我们已经完成了实现的抽象部分。
实时示例
我们将实现 3 个类(其中一个仅用于方便)。 第一个类是 Broker
' Class Broker
' one of the model's participants
Public Class Broker
Private _name As String
Private _balance As Decimal
Private _acc As New BrokerAccount(Me)
Public ReadOnly Property Account() As BrokerAccount
Get
Return _acc
End Get
End Property
Public Sub New()
End Sub
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal Value As String)
_name = Value
End Set
End Property
Public Property Balance() As Decimal
Get
Return _balance
End Get
Set(ByVal Value As Decimal)
_balance = Value
End Set
End Property
End Class 'Broker
第二个类是 BrokerAccount
– 一个负责更改 Broker
余额的类。
Public Class BrokerAccount
Inherits Subject
Private _br As Broker
Public Class InvalidBalanceException
Inherits Exception
Public Sub New()
MyBase.New("Broker balance is less than debited amount!")
End Sub
End Class
Public Sub New(ByRef br As Broker)
_br = br
End Sub
Public Sub Credit(ByVal adAmount As Decimal)
_br.Balance += adAmount
MyBase.Notify()
End Sub
Public Sub Debit(ByVal adAmount As Decimal)
If _br.Balance - adAmount < 0 Then
Throw New InvalidBalanceException()
Else
_br.Balance -= adAmount
MyBase.Notify()
End If
End Sub
End Class 'BrokerAccount
和一个辅助类 - Broker 对象的集合。
Public Class BrokerCollection
Inherits ArrayList
Default Public Overrides Property Item(ByVal index As Integer) As Object
Get
Return MyBase.Item(index)
End Get
Set(ByVal Value As Object)
If Not TypeOf Value Is Broker Then
Throw New Exception("Can't hold objects of other than Broker type")
Else
MyBase.Item(index) = Value
End If
End Set
End Property
Public Overrides Function Add(ByVal value As Object) As Integer
If Not TypeOf value Is Broker Then
Throw New Exception("Can't hold objects of other than Broker type")
Else
Return MyBase.Add(value)
End If
End Function
End Class
提供的示例 (MV_Form
) 让你快速了解如何在 Windows Forms 应用程序中使用此模式
Public Class Form1
Inherits System.Windows.Forms.Form
Implements MV_Objects.Observer
Form_Load
事件:在这里,我们初始化一个 ListView
控件,其中包含 10 个经纪人的列表。 每个列表视图都通过其 Tag
属性(确实非常有用:))与一个 Broker
对象关联
For i = 1 To 10
br = New Broker()
br.Name = "broker " & i
br.Account.AddObserver(Me)
itm = New ListViewItem(New String() {br.Name, br.Balance})
itm.Tag = br
lvBr.Items.Add(itm)
_brcol.Add(br)
Next
以下 sub
实现了 Observer
接口的 Update
方法。 它找到了与 ListView
中的某个经纪人关联的条目,并更新了 balance
列。
Public Sub UpdateBrokers(ByVal subj As Object) _
Implements MV_Objects.Observer.Update
Dim br As Broker, itm As ListViewItem
For Each itm In lvBr.Items
br = itm.Tag
If br.Account Is subj Then
itm.SubItems(1).Text = br.Balance
End If
Next
End Sub
表单上还有 2 个按钮和一个文本框。 它们的实现很简单,为了具体起见,本文中没有介绍。
结束
就这样! 运行随附的示例应用程序以查看其工作原理。 您可以在 BrokerAccount
类的 Credit
和 Debit
方法上放置一个断点,并使用调试器逐步执行。 这确实是一个简单但强大的模式,可以用于更多目的。 欢迎您在论坛中提及它们 :)
还可以添加到这个小型项目中的另一件事是将每个更新过程放在一个单独的线程中。 当被监视的对象数量很少时,这没问题,但在其他情况下会失败。 对于这个问题(当对象数量超过 50,000 个时),欢迎提出任何提示。
致谢
本文基于 James Maioriello 博士的工作,他在其中描述了基本的设计模式。 抱歉,我不记得是从哪里获得的,但无论如何,我确实承认了这一点 :)