观察者模式 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();
}
}
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);
}
}
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();
}
}
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.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.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
}
}
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(11, 22, 33);
weatherData.SetMessurement(111, 222, 333);
weatherData.SetMessurement(1111, 2222, 3333);
}
}
}
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(11, 22, 33);
weatherData.SetMessurement(111, 222, 333);
weatherData.SetMessurement(1111, 2222, 3333);
}
}
}
结果:
[注]:类图中的继承应该是虚线,Rose掌握不熟,另外实心线带箭头表示,两者有关系,如图中ISubject箭头指向IObject,两者有关系,ISubject有IObject类型变量