williambirkin

恭喜发财!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

意图

定义对象间一对多的关系,一个对象变化时,所有依赖它的对象都得到通知并被自动更新。一个最典型的例子就是Windows中的音量控制器,我们可以打开多个音量控制器窗口。当其中一个变化的时候,其余均随之变化。

 

使用场合

改变一个对象需要通知其他对象,而不知道有多少个对象有待改变

一个对象必须通知其他对象,而又不能假定这些对象,几不希望这些对象是紧密耦合的。

结构

Subject(目标):知道观察者,可以有多个任意多个观察者观察一个目标。

Observer(观察者):为观察者定一个更新接口。

ConcreteSubject(具体目标):根据ConcreteSubject更新观察者。

ConcreteObserver(具体对象观察者):根据ConcreteSubject更新观察者。 

这是传统的观察者模式结构,如果采用委托技术,则Subject不需要知道Observer的存在,这时只要将Notify委托给Observer对象即可。

效果

采用观察者模式的优点是降低了目标和观察者之间的耦合性。如果采用.NET的委托和事件机制实现观察者模式,可以使目标和观察者之间没有静态的耦合关系。

由于观察者模式不限定观察者的数量,因此可以支持广播,目标发送信息时不需要制定观察者。

采用委托和事件机制实现观察者模式

然而采用观察者模式的代价就是如果通讯设计不当,会产生意想不到的连锁反应。由于观察者模式动态执行,所以这种连锁反应很难调试,常见的连锁异常出现在事件处理上。


模拟声音控制器

声音控制类:

using System;
using System.Collections.Generic;
using System.Text;

namespace ObserverPattern
{
    
public class VolumeControl
    
{
        
//代理变化事件的代理
        public delegate void VolumeChangeEvent(int v);
        
//音量变化的事件
        public event VolumeChangeEvent VolumeChanged;
        
private int volume = 0;

        
/// <summary>
        
/// 音量
        
/// </summary>

        public int Volume
        
{
            
get return volume; }
            
set
            
{
                volume 
= value;
                
if (VolumeChanged != null)
                
{
                    VolumeChanged(volume);
                }

            }

        }

    }

}


声音控制面板窗体:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace ObserverPattern
{
    
public partial class FrmSub : Form
    
{
        
private VolumeControl vc1;
        
private VolumeControl vc2;

        
public FrmSub(VolumeControl v1, VolumeControl v2)
        
{
            InitializeComponent();
            vc1 
= v1;
            vc2 
= v2;
        }


        
private void FrmSub_Load(object sender, EventArgs e)
        
{

        }


        
public void ChangeVolume1(int v)
        
{
            vScrollBar1.Value 
= v;
        }


        
public void ChangeVolume2(int v)
        
{
            vScrollBar2.Value 
= v; 
        }


        
private void vScrollBar1_ValueChanged(object sender, EventArgs e)
        
{
            vc1.Volume 
= vScrollBar1.Value;
        }


        
private void vScrollBar2_ValueChanged(object sender, EventArgs e)
        
{
            vc2.Volume 
= vScrollBar2.Value;
        }


        
private void FrmSub_FormClosed(object sender, FormClosedEventArgs e)
        
{
            
//注销事件
            vc1.VolumeChanged -= new VolumeControl.VolumeChangeEvent(ChangeVolume1);
            vc2.VolumeChanged 
-= new VolumeControl.VolumeChangeEvent(ChangeVolume2);
        }

    }

}


测试窗体:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace ObserverPattern
{
    
public partial class Form1 : Form
    
{
        
private VolumeControl vc1;
        
private VolumeControl vc2;

        
public Form1()
        
{
            InitializeComponent();
            vc1 
= new VolumeControl();
            vc2 
= new VolumeControl();
        }


        
private void button1_Click(object sender, EventArgs e)
        
{            
            FrmSub fs 
= new FrmSub(vc1,vc2);

            
//注册事件
            vc1.VolumeChanged += new VolumeControl.VolumeChangeEvent(fs.ChangeVolume1);
            vc2.VolumeChanged 
+= new VolumeControl.VolumeChangeEvent(fs.ChangeVolume2);

            fs.Show();
        }

    }

}


事件连锁

使用察者模式及事件委托,需要注意连锁情况。如果理不当,则发生“死”,即使程序入死循生死的原因有多,最常见的是两个对象的状态需要保持一致,并且二者互为主题和观察者。其中一个发生变化,另一个也随之变化。当某种条件导致循环调用时,会产生死锁。

 

相关模式

中介者模式:如果观察者和被观察者之间的主题关系复杂,则需要引入变化管理器,这时变化管理器起着中介者的作用。
posted on 2007-02-08 15:09  williambirkin  阅读(346)  评论(0编辑  收藏  举报