|
在現(xiàn)實(shí)世界中,許多對象并不是獨(dú)立存在的,其中一個(gè)對象的行為發(fā)生改變可能會導(dǎo)致一個(gè)或者多個(gè)其他對象的行為也發(fā)生改變。例如,某種商品的物價(jià)上漲時(shí)會導(dǎo)致部分商家高興,而消費(fèi)者傷心。 在軟件世界也是這樣,例如,事件模型中的事件源與事件處理者。所有這些,如果用觀察者模式來實(shí)現(xiàn)就非常方便。 定義與特點(diǎn)觀察者(Observer)模式的定義:指多個(gè)對象間存在一對多的依賴關(guān)系,當(dāng)一個(gè)對象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對象都得到通知并被自動更新。這種模式有時(shí)又稱作發(fā)布-訂閱模式、模型-視圖模式,它是對象行為型模式。 觀察者模式是一種對象行為型模式,其主要優(yōu)點(diǎn)如下:
它的主要缺點(diǎn)如下:
結(jié)構(gòu)與實(shí)現(xiàn)實(shí)現(xiàn)觀察者模式時(shí)要注意具體目標(biāo)對象和具體觀察者對象之間不能直接調(diào)用,否則將使兩者之間緊密耦合起來,這違反了面向?qū)ο蟮脑O(shè)計(jì)原則。 模式的結(jié)構(gòu)觀察者模式的主要角色如下:
觀察者模式的結(jié)構(gòu)圖如圖所示:
模式的實(shí)現(xiàn)觀察者模式的實(shí)現(xiàn)代碼如下: class Program
{
static void Main(string[] args)
{
Subject subject=new ConcreteSubject();
IObserver obs1=new ConcreteObserver1();
IObserver obs2=new ConcreteObserver2();
subject.Add(obs1);
subject.Add(obs2);
subject.NotifyObserver();
Console.Read();
}
}
//抽象目標(biāo)
public abstract class Subject
{
protected List<IObserver> observers=new List<IObserver>();
//增加觀察者方法
public void Add(IObserver observer)
{
observers.Add(observer);
}
//刪除觀察者方法
public void Remove(IObserver observer)
{
observers.Remove(observer);
}
public abstract void NotifyObserver(); //通知觀察者方法
}
//具體目標(biāo)
public class ConcreteSubject : Subject
{
public override void NotifyObserver()
{
Console.WriteLine("具體目標(biāo)發(fā)生改變...");
Console.WriteLine("--------------");
foreach (var obs in observers)
{
obs.Response();
}
}
}
//抽象觀察者
public interface IObserver
{
void Response(); //反應(yīng)
}
//具體觀察者1
public class ConcreteObserver1 : IObserver
{
public void Response()
{
Console.WriteLine("具體觀察者1作出反應(yīng)!");
}
}
//具體觀察者1
public class ConcreteObserver2 : IObserver
{
public void Response()
{
Console.WriteLine("具體觀察者2作出反應(yīng)!");
}
}程序運(yùn)行結(jié)果如下: 具體目標(biāo)發(fā)生改變... -------------- 具體觀察者1作出反應(yīng)! 具體觀察者2作出反應(yīng)! 應(yīng)用場景通過前面的分析與應(yīng)用實(shí)例可知觀察者模式適合以下幾種情形:
擴(kuò)展:.net中的IObservable和 IObserver接口在.net環(huán)境下,其運(yùn)行時(shí)庫為開發(fā)者提供了IObservable和 IObserver接口,用于實(shí)現(xiàn)觀察者模式軟件設(shè)計(jì)。另外,ObservableCollection 類表示一個(gè)動態(tài)數(shù)據(jù)集合,它可在添加、刪除項(xiàng)目或刷新整個(gè)列表時(shí)提供通知。
注:在 Java 中,通過 java.util.Observable 類和 java.util.Observer 接口定義了觀察者模式,只要實(shí)現(xiàn)它們的子類就可以編寫觀察者模式實(shí)例。 下面的示例演示觀察者設(shè)計(jì)模式,實(shí)現(xiàn)定位系統(tǒng)實(shí)時(shí)通知當(dāng)前經(jīng)緯度坐標(biāo),代碼如下: class Program
{
static void Main(string[] args)
{
// 定義一個(gè)提供者和兩個(gè)觀察者
LocationTracker provider = new LocationTracker();
LocationReporter reporter1 = new LocationReporter("FixedGPS");
reporter1.Subscribe(provider);
LocationReporter reporter2 = new LocationReporter("MobileGPS");
reporter2.Subscribe(provider);
provider.TrackLocation(new Location(47.6456, -122.1312));
reporter1.Unsubscribe();
provider.TrackLocation(new Location(47.6677, -122.1199));
provider.TrackLocation(null);
provider.EndTransmission();
Console.Read();
}
}
/// <summary>
/// 位置:包含緯度和經(jīng)度信息
/// </summary>
public struct Location
{
double lat, lon;
public Location(double latitude, double longitude)
{
this.lat = latitude;
this.lon = longitude;
}
/// <summary>
/// 緯度
/// </summary>
public double Latitude
{ get { return this.lat; } }
/// <summary>
/// 經(jīng)度
/// </summary>
public double Longitude
{ get { return this.lon; } }
}
/// <summary>
/// 位置報(bào)告者:提供 IObserver<T> 實(shí)現(xiàn),它顯示有關(guān)當(dāng)前控制臺位置的信息
/// </summary>
public class LocationReporter : IObserver<Location>
{
private IDisposable unsubscriber;
private string instName;
public LocationReporter(string name)
{
this.instName = name;
}
public string Name
{ get { return this.instName; } }
/// <summary>
/// 訂閱:將由對 Subscribe 的調(diào)用返回的 IDisposable 實(shí)現(xiàn)保存到私有變量中
/// </summary>
/// <param name="provider"></param>
public virtual void Subscribe(IObservable<Location> provider)
{
if (provider != null)
unsubscriber = provider.Subscribe(this);
}
public virtual void OnCompleted()
{
Console.WriteLine("位置跟蹤器已將數(shù)據(jù)傳輸?shù)?nbsp;{0}", this.Name);
this.Unsubscribe();
}
public virtual void OnError(Exception e)
{
Console.WriteLine("{0}: 無法確定位置", this.Name);
}
public virtual void OnNext(Location value)
{
Console.WriteLine("{2}: 當(dāng)前位置是 {0}, {1}", value.Latitude, value.Longitude, this.Name);
}
/// <summary>
/// 退訂:使類可以通過調(diào)用提供程序的 Dispose 實(shí)現(xiàn)來取消訂閱通知
/// </summary>
public virtual void Unsubscribe()
{
unsubscriber.Dispose();
}
}
/// <summary>
/// 位置跟蹤器:提供 IObservable<T> 實(shí)現(xiàn)
/// </summary>
public class LocationTracker : IObservable<Location>
{
public LocationTracker()
{
observers = new List<IObserver<Location>>();
}
private List<IObserver<Location>> observers;
/// <summary>
/// 訂閱:某觀察程序?qū)⒁邮胀ㄖ? /// </summary>
/// <param name="observer"></param>
/// <returns></returns>
public IDisposable Subscribe(IObserver<Location> observer)
{
if (!observers.Contains(observer))
observers.Add(observer);
return new Unsubscriber(observers, observer);
}
/// <summary>
/// IDisposable 實(shí)現(xiàn):用于刪除觀察者或取消訂閱
/// </summary>
private class Unsubscriber : IDisposable
{
private List<IObserver<Location>> _observers;
private IObserver<Location> _observer;
public Unsubscriber(List<IObserver<Location>> observers, IObserver<Location> observer)
{
this._observers = observers;
this._observer = observer;
}
public void Dispose()
{
if (_observer != null && _observers.Contains(_observer))
_observers.Remove(_observer);
}
}
public void TrackLocation(Nullable<Location> loc)
{
foreach (var observer in observers)
{
if (!loc.HasValue)
observer.OnError(new LocationUnknownException());
else
observer.OnNext(loc.Value);
}
}
public void EndTransmission()
{
foreach (var observer in observers.ToArray())
{
if (observers.Contains(observer))
observer.OnCompleted();
}
observers.Clear();
}
}
/// <summary>
/// 位置未知異常
/// </summary>
public class LocationUnknownException : Exception
{
internal LocationUnknownException()
{ }
}程序運(yùn)行結(jié)果如下: FixedGPS:當(dāng)前位置是47.6456,-122.1312 MobileGPS:當(dāng)前位置是47.6456,-122.1312 MobileGPS:當(dāng)前位置是47.6677,-122.1199 MobileGPS:無法確定位置位置 跟蹤器已將數(shù)據(jù)傳輸?shù)組obileGPS |
|
|