OO原則:
為交互對象之間的松耦合設計而努力
OO模式:
觀察者模式(Observer),在對象之間定義一對多依賴,這樣一來,當一個對象改變狀態,依賴它的對象都會收到通知,并自動更新
類結構圖:
氣象站項目代碼
定義主體接口:
/// <summary>
/// 定義主題對象接口
/// </summary>
public interface ISubject
{
//註冊一個觀測者
void RegisterObserver(IObserver observer);
//移除一個觀測者
void RemoveObserver(IObserver observer);
//通知所有觀測者跟新數據
void NotifyObservers();
//設定是否通知觀測者更新
void SetChanged();
}
定義觀測者接口:
/// <summary>
/// 定義觀測者接口
/// </summary>
public interface IObserver
{
//以拉的方式,主動從主題獲取所需要的數據
void Update(ISubject subject);
//以推的方式,被動接受主題傳來的信息
void Update(float temp, float humidity, float pressure);
}
定義佈告板顯示接口:
/// <summary>
/// 定義佈告板顯示接口
/// </summary>
public interface IDisplayElement
{
void Display();
}
WeatherData主體類:
using System.Collections;
/// <summary>
/// WeatherData 主題對象
/// </summary>
public class WeatherData : ISubject
{
//訂閱者列表
private ArrayList observers;
//數據字段
private float temperature;
private float humidity;
private float pressure;
//是否通知觀測者更新
private bool changed = false;
public float Temperature
{ get { return this.temperature; } }
public float Humidity
{ get { return this.humidity; } }
public float Pressure
{ get { return this.pressure; } }
//構造函數
public WeatherData()
{
observers = new ArrayList();
}
//當從氣象站得到更新數據時,通知所有觀測者
public void MeasurementsChanged()
{
NotifyObservers();
}
//測試用模擬更新數據
public void SetMeasurements(float temperature, float humidity, float pressure)
{
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
MeasurementsChanged();
}
#region 實現接口
//註冊觀測者
public void RegisterObserver(IObserver observer)
{
//加入觀測者
observers.Add(observer);
}
//註銷觀測者
public void RemoveObserver(IObserver observer)
{
//移除觀測者
int i = observers.IndexOf(observer);
if (i >= 0) {
observers.Remove(i);
}
}
//主題更新,通知所有觀測者
public void NotifyObservers()
{
if (changed)
{
foreach (IObserver observer in observers)
{
//調用每個觀測者的更新方法
//observer.Update(temperature, humidity, pressure);
observer.Update(this);
}
changed = false;
}
}
//設定是否通知觀測者更新
public void SetChanged()
{
changed = true;
}
#endregion
}
第一號佈告板,目前狀況類:
/// <summary>
/// CurrentConditionsDisplay 第一號佈告板:目前狀況
/// </summary>
public class CurrentConditionsDisplay : IObserver, IDisplayElement
{
//觀測者持有主題引用
private ISubject subject;
//佈告板私有數據字段
private float temperature;
private float humidity;
private float pressure;
//構造函數
public CurrentConditionsDisplay(ISubject subject)
{
this.subject = subject;
}
//以拉的方式主動獲取數據
public void Update(ISubject subject)
{
WeatherData wd = subject as WeatherData;
if (wd != null)
{
this.temperature = wd.Temperature;
this.humidity = wd.Humidity;
this.pressure = wd.Pressure;
Display();
}
}
//以拖的方式被動接受數據
public void Update(float temp, float humidity, float pressure)
{
//throw new System.NotImplementedException();
}
//顯示信息
public void Display()
{
System.Web.HttpContext.Current.Response.Write("<br/>觀測者CurrentConditionsDisplay獲取新數據:"
+ this.temperature + "," + this.humidity + "," + this.pressure);
}
}
第二號佈告板,氣象統計類:
/// <summary>
/// StatisticsDisplay 第二號佈告板:氣象統計
/// </summary>
public class StatisticsDisplay : IObserver, IDisplayElement
{
//觀測者持有主題引用
private ISubject subject;
//佈告板私有數據字段
private float temperature;
//構造函數
public StatisticsDisplay(ISubject subject)
{
this.subject = subject;
}
//以拉的方式主動獲取數據
public void Update(ISubject subject)
{
WeatherData wd = subject as WeatherData;
if (wd != null)
{
this.temperature = wd.Temperature;
Display();
}
}
//以拖的方式被動接受數據
public void Update(float temp, float humidity, float pressure)
{
//throw new System.NotImplementedException();
}
//顯示信息
public void Display()
{
System.Web.HttpContext.Current.Response.Write("<br/>觀測者StatisticsDisplay獲取新數據:"
+ this.temperature);
}
}
調用:
public partial class Observer : System.Web.UI.Page
{
//主題對象
private static WeatherData wd = new WeatherData();
//觀測者
private static CurrentConditionsDisplay ccd;
private static StatisticsDisplay sd;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
wd.SetChanged();
ccd = new CurrentConditionsDisplay(wd);
wd.RegisterObserver(ccd);
sd = new StatisticsDisplay(wd);
wd.RegisterObserver(sd);
}
}
protected void Button1_Click(object sender, EventArgs e)
{
wd.SetMeasurements(DateTime.Now.Second, DateTime.Now.Second + 1, DateTime.Now.Second + 2);
}
}