Design Patterns(二十):Observer Pattern--VB代码

本文介绍观察者模式的核心概念与应用场景,通过示例代码展示了如何利用该模式实现对象间的依赖关系,使得当一个对象状态变化时,所有依赖对象都能自动更新。

结构图

 

角色

  • 抽象主题(Subject)角色:主题角色把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,主题角色又叫做抽象被观察者(Observable)角色。
  • 抽象观察者(ConcreteSubject)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。
  • 具体主题(Observer)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者角色(Concrete Observable)。
  • 具体观察者(ConcreteObserver)角色:存储与主题的状态自洽的状态。具体观察者角色事项抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题对象的引用。

动机

  在软件构建过程中集合,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些公有接口来让其他对象得到对象的状态,便会暴露对象的细节实现。
    如何实现对象状态的良好保存与恢复?但同时又不会因此而破坏对象本身的封装性。

意图

  
定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。

示意性代码

示意性代码
'MainApp test application
Module MainApp
    
Public Sub Main()
        
'Configure Observer pattern
        Dim s As ConcreteSubject = New ConcreteSubject()

        s.Attach(
New ConcreteObserver(s, "X"))
        s.Attach(
New ConcreteObserver(s, "Y"))
        s.Attach(
New ConcreteObserver(s, "Z"))

        
'Change subject and notify observers 
        s.SubjectState = "ABC"
        s.Notify()

        
'Wait for user
        Console.ReadLine()
    
End Sub
End Module

' "Subject" 
Public MustInherit Class Subject
    
Private observers As New List(Of Observer)

    
Public Sub Attach(ByVal observer As Observer)
        observers.Add(observer)
    
End Sub

    
Public Sub Detach(ByVal observer As Observer)
        observers.Remove(observer)
    
End Sub

    
Public Sub Notify()
        
For Each o As Observer In observers
            o.update()
        
Next
    
End Sub

End Class

'"ConcreteSubject" 
Public Class ConcreteSubject
    
Inherits Subject
    
Private _subjectState As String
    
'Property 
    Public Property SubjectState() As String
        
Get
            
Return _subjectState
        
End Get
        
Set(ByVal value As String)
            _subjectState 
= value
        
End Set
    
End Property
End Class

'"Observer"
Public MustInherit Class Observer
    
MustOverride Sub update()
End Class

'"ConcreteObserver" 
Public Class ConcreteObserver
    
Inherits Observer
    
Private _name As String
    
Private observerState As String
    
Private _subject As ConcreteSubject
    
'Constructor 
    Public Sub New(ByVal subject As ConcreteSubject, ByVal name As String)
        
Me._subject = subject
        
Me._name = name
    
End Sub

    
'Property 
    Public Property Subject() As ConcreteSubject
        
Get
            
Return _subject
        
End Get
        
Set(ByVal value As ConcreteSubject)
            _subject 
= value
        
End Set
    
End Property

    
Public Overrides Sub Update()
        observerState 
= _subject.SubjectState
        Console.WriteLine(
"Observer {0}'s new state is {1}", _
          _name, observerState)
    
End Sub

End Class

 

 一个实例

 下面的观察者代码演示了投资者登记后,每次股价发生变化,都会得到通知。

实例代码
Module MainApp
    
Public Sub MainApp()
        
'Create investors 
        Dim s As New Investor("Sorros")
        
Dim b As New Investor("Berkshire")

        
'Create IBM stock and attach investors 
        Dim ibm As New IBM("IBM"120.0)
        ibm.Attach(s)
        ibm.Attach(b)

        
'Change price, which notifies investors
        ibm.Price = 121.1
        ibm.Price 
= 122.0
        ibm.Price 
= 123.5
        ibm.Price 
= 124.75

        
'Wait for user
        Console.ReadLine()
    
End Sub
End Module

'"Subject"
Public MustInherit Class Stock

    
Private _Price As Double
    
Private _Symbol As String
    
Private investors As New List(Of Investor)

    
'Constructor
    Sub New(ByVal symbol As StringByVal price As Double)
        _Symbol 
= symbol
        _Price 
= price
    
End Sub

    
'Properties
    Public Property Price() As Double
        
Get
            
Return _Price
        
End Get
        
Set(ByVal value As Double)
            _Price 
= value
            Notify()
        
End Set
    
End Property

    
Public Property Symbol() As String
        
Get
            
Return _Symbol
        
End Get
        
Set(ByVal value As String)
            _Symbol 
= value
        
End Set
    
End Property

    
Public Sub Attach(ByVal investor As Investor)
        investors.Add(investor)
    
End Sub

    
Public Sub Detach(ByVal investor As Investor)
        investors.Remove(investor)
    
End Sub

    
Public Sub Notify()
        
For Each investor As Investor In investors
            investor.Update(
Me)
        
Next
        Console.WriteLine(
"")
    
End Sub
End Class

'"ConcreteObject"
Public Class IBM
    
Inherits Stock

    
'Constructor
    Sub New(ByVal symbol As StringByVal price As Double)
        
MyBase.New(symbol, price)
    
End Sub
End Class

'"Observer"
Public Interface IInvestor
    
Sub Update(ByVal stock As Stock)
End Interface

'"ConcreteObserver"
Public Class Investor
    
Implements IInvestor

    
Private _Stock As Stock
    
Private name As String

    
'Constructor
    Sub New(ByVal name As String)
        
Me.name = name
    
End Sub

    
Public Property Stock() As Stock
        
Get
            
Return _Stock
        
End Get
        
Set(ByVal value As Stock)
            _Stock 
= value
        
End Set
    
End Property

    
Public Sub Update(ByVal stock As Stock) Implements IInvestor.Update
        Console.WriteLine(
"Notified {0} of {1}'s " & "change to {2:C}", _
            name, stock.Symbol, stock.Price)
    
End Sub
End Class

 

 改进后的代码

 用.Net的事件委托实现上面的实例

改进后的代码
Module MainApp
    
Public Sub Main()

        
'Create investors 
        Dim s As New Investor("Sorros")
        
Dim b As New Investor("Berkshire")

        
'Create IBM stock and attach investors 
        Dim ibm As New IBM("IBM"120.0)
        ibm.Attach(s)
        ibm.Attach(b)

        
'Change price, which notifies investors
        ibm.Price = 121.1
        ibm.Price 
= 122.0
        ibm.Price 
= 123.5
        ibm.Price 
= 124.75

        
'Wait for user
        Console.ReadLine()
    
End Sub
End Module

'"Subject"
Public MustInherit Class Stock

    
Private _Price As Double
    
Private _Symbol As String
    
Private Event InvesteEvent(ByVal symbol As StringByVal price As Double)
    
'Constructor
    Sub New(ByVal symbol As StringByVal price As Double)
        _Symbol 
= symbol
        _Price 
= price
    
End Sub

    
'Properties
    Public Property Price() As Double
        
Get
            
Return _Price
        
End Get
        
Set(ByVal value As Double)
            _Price 
= value
            Notify()
        
End Set
    
End Property

    
Public Property Symbol() As String
        
Get
            
Return _Symbol
        
End Get
        
Set(ByVal value As String)
            _Symbol 
= value
        
End Set
    
End Property

    
Public Sub Attach(ByVal investor As IInvestor)
        
AddHandler InvesteEvent,AddressOf investor.Update
    
End Sub

    
Public Sub Detach(ByVal investor As IInvestor)
        
RemoveHandler InvesteEvent,AddressOf investor.Update
    
End Sub

    
Public Sub Notify()
        OnInveste
        Console.WriteLine(
"")
    
End Sub
    
    
Protected Sub OnInveste()
        
RaiseEvent InvesteEvent(_symbol,_Price)
    
End Sub
End Class

'"ConcreteSbject"
Public Class IBM
    
Inherits Stock

    
'Constructor
    Sub New(ByVal symbol As StringByVal price As Double)
        
MyBase.New(symbol, price)
    
End Sub
End Class

'"Observer"
Public Interface IInvestor
    
Sub Update(ByVal symbol As StringByVal price As Double)
End Interface

'"ConcreteObserver"
Public Class Investor
    
Private name As String

    
'Constructor
    Sub New(ByVal name As String)
        
Me.name = name
    
End Sub

    
Public Sub Update(ByVal symbol As StringByVal price As DoubleImplements IInvestor.Update
        Console.WriteLine(
"Notified {0} of {1}'s " & "change to {2:C}", _
            name, Symbol, Price)
    
End Sub
End Class

 

Observer Pattern模式的几个要点:
   1、使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。
   2、目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。观察者自己决定是不需要订阅通知,目标对象对此一无所知。
     3、在C#的event中,委托充当了抽象的Observer接口,而提供事件的对象充当了目标对象。委托是比抽象Observer更为松耦合的设计。

我的理解

封装对象通知,支持通信对象的变化。

参考资料
《C#面向对象设计模式纵横谈系列课程(21)》     李建中老师

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值