代码改变世界

观察者模式 Observer

2011-07-05 01:13  三皮开发时  阅读(275)  评论(0编辑  收藏  举报

举例说明该模式的应用场:

 

1.比方说有个气象站,气象站的功能就是会收集气象信息,温度、湿度、气压等;现在有3个关于天气的布告栏,由于各地的生活环境、方式不一样,所以显示的数据信息也各有所异,比如:

①号布告栏显示温度和湿度就行         :温度、湿度

②号布告栏显示气压                             :气压

③号布告栏显示气象站的全部信息     :温度、湿度、气压

要求是气象站一有新的气象数据立马更新3个布告栏,使信息同步准确,这种需求如何设计呢?

 

2.再举个应用场景,如报社和读者之间的关系,只要读者订阅了报社业务,报社就会如期给读者送去报纸,读者也可以根据自己的需要订阅自己喜欢的类型信息,如订阅财经、军事、政治等不同类型报纸,这种类型的业务如何设计呢? 先想想

 

分析:

ISubject  报社接口,实现注册对象、移除对象、向注册的对象发送报纸

IObserver、IDisplay 读者接口

 

结合代码:

ISubject 接口

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

namespace ObserverMode.IDAL
{
    
/// <summary>
    
/// 主题接口(相当于报社,一有数据更新及时通知订阅者)
    
/// <para>包含的功能主要有:</para>
    
/// <para>1.注册对象(订阅者)</para>
    
/// <para>2.移除对象</para>
    
/// <para>3.通知对象</para>
    
/// </summary>
    public interface ISubject
    {
         
void RegisterObserver(IObserver o);
         
void RemoveObserver(IObserver o);
         
void NotifyObserver();
    }
}

 

IObserver接口

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

namespace ObserverMode.IDAL
{
    
/// <summary>
    
/// 观察者接口(订阅者)
    
/// <para>功能:更新数据,比如报社有了新数据过来,订阅者及时更新</para>
    
/// </summary>
    public interface IObserver
    {
        
/// <summary>
        
/// 更新数据
        
/// </summary>
        
/// <param name="temp">温度</param>
        
/// <param name="humidity">湿度</param>
        
/// <param name="pressure">气压</param>
        void Update(float temp,float humidity,float pressure);
    }
}

 

IDisplay接口

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

namespace ObserverMode.IDAL
{
    
/// <summary>
    
/// 显示信息接口
    
/// <para>描述:刚开始有个疑问,为什么单独需要一个显示信息接口?</para>
    
/// <para>单独有这个接口是因为不同的预订者想呈现的数据是不一样的
    
/// <para>不同的预订者想看的报社新闻各有不同,关注的东西都不一样,</para>
    
/// <para>所以不同的观察者Display都不同,因此需要这个display接口</para>
    
/// </summary>
    public interface IdisplayElement
    {
        
void Disyplay();
    }
}

 

 

WeatherData 类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using ObserverMode.IDAL;

namespace ObserverMode
{
    
/// <summary>
    
/// 主题类,可以理解为报社
    
/// </summary>
    public class WeatherData : ISubject
    {
        
#region 变量
        
/// <summary>
        
/// 观察者集合
        
/// </summary>
        private ArrayList observers;

        
/// <summary>
        
/// 温度
        
/// </summary>
        private float temperature;

        
/// <summary>
        
/// 湿度
        
/// </summary>
        private float humidity;

        
/// <summary>
        
/// 气压
        
/// </summary>
        private float pressure;
        
#endregion
        
        
/// <summary>
        
/// 构造函数
        
/// </summary>
        public WeatherData()
        {
            observers 
= new ArrayList();
        }



        
#region ISubject 成员

        
/// <summary>
        
/// 添加观察者
        
/// </summary>
        
/// <param name="o">预订者</param>
        public void RegisterObserver(IObserver o)
        {
            observers.Add(o);
        }

        
/// <summary>
        
/// 移除观察者
        
/// </summary>
        
/// <param name="o"></param>
        public void RemoveObserver(IObserver o)
        {
            
#region Java
            
//int i = observers.IndexOf(o);
            
//if (i >= 0)
            
//{
            
//    observers.Remove(i);
            
//}
            #endregion           

            
//C#
            if (observers.Contains(o))
            {
                observers.Remove(o);
            }
        }

        
/// <summary>
        
/// 通知观察者
        
/// </summary>
        public void NotifyObserver()
        {
            
for (int i = 0; i < observers.Count; i++)
            {
                IObserver observer 
= (IObserver)observers[i];
                observer.Update(temperature, humidity, pressure);
            }
        }

        
/// <summary>
        
/// 当报社得到最新消息时,我们就通知观察者
        
/// </summary>
        public void MeasurementsChanged()
        {
            NotifyObserver();
        }

        
/// <summary>
        
/// 设置值,并告知预订者
        
/// </summary>
        
/// <param name="temperature"></param>
        
/// <param name="humidity"></param>
        
/// <param name="pressure"></param>
        public void SetMessurement(float temperature, float humidity, float pressure)
        {
            
this.temperature = temperature;
            
this.humidity = humidity;
            
this.pressure = pressure;
            MeasurementsChanged();
        }
        
#endregion
    }
}

 

①号布告栏

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ObserverMode.IDAL;

namespace ObserverMode
{
    
/// <summary>
    
/// 预订者A
    
/// </summary>
    public class UserA:IObserver,IdisplayElement
    {
        
private float temperature;
        
private float humidity;
        
private ISubject weatherData;

        
public UserA(ISubject weatherData)
        {
            
this.weatherData = weatherData;
            weatherData.RegisterObserver(
this);
        }


        
#region IObserver 成员

        
public void Update(float temp, float humidity, float pressure)
        {
            
this.temperature = temp;
            
this.humidity = humidity;
            Disyplay();
        }

        
#endregion

        
#region IdisplayElement 成员

        
public void Disyplay()
        {
            Console.WriteLine(
"我是用户A,我只关心温度和湿度情况,当前温度为:"+temperature+" 湿度为:"+humidity);
        }

        
#endregion
    }
}

 

②号布告栏

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ObserverMode.IDAL;

namespace ObserverMode
{
    
public class UserB:IObserver,IdisplayElement
    {
        
private float pressure;
        
private ISubject subject;
        
public UserB(ISubject subject)
        {
            
this.subject = subject;
            subject.RegisterObserver(
this);
        }
        
#region IdisplayElement 成员

        
public void Disyplay()
        {
            Console.WriteLine(
"我是用户B,我只对气压感兴趣,当前气压值为:"+pressure);
        }

        
#endregion

        
#region IObserver 成员

        
public void Update(float temp, float humidity, float pressure)
        {
            
this.pressure = pressure;
            Disyplay();
        }

        
#endregion
    }
}

 

Main()

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

namespace ObserverMode
{
    
class Program
    {
        
static void Main(string[] args)
        {
            WeatherData weatherData 
= new WeatherData();
            UserA userA 
= new UserA(weatherData);
            UserB userB 
= new UserB(weatherData);

            
//weatherData.RemoveObserver(userB);         
            weatherData.SetMessurement(
112233);
            weatherData.SetMessurement(
111222333);
            weatherData.SetMessurement(
111122223333);
        }
    }
}

 

结果:

 

 

[注]:类图中的继承应该是虚线,Rose掌握不熟,另外实心线带箭头表示,两者有关系,如图中ISubject箭头指向IObject,两者有关系,ISubject有IObject类型变量