|
在現(xiàn)實世界中,許多對象并不是獨立存在的,其中一個對象的行為發(fā)生改變可能會導致一個或者多個其他對象的行為也發(fā)生改變。例如,某種商品的物價上漲時會導致部分商家高興,而消費者傷心。 在軟件世界也是這樣,例如,事件模型中的事件源與事件處理者。所有這些,如果用觀察者模式來實現(xiàn)就非常方便。 定義與特點觀察者(Observer)模式的定義:指多個對象間存在一對多的依賴關系,當一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新。這種模式有時又稱作發(fā)布-訂閱模式、模型-視圖模式,它是對象行為型模式。 觀察者模式是一種對象行為型模式,其主要優(yōu)點如下:
它的主要缺點如下:
結構與實現(xiàn)實現(xiàn)觀察者模式時要注意具體目標對象和具體觀察者對象之間不能直接調用,否則將使兩者之間緊密耦合起來,這違反了面向對象的設計原則。 模式的結構觀察者模式的主要角色如下:
觀察者模式的結構圖如圖所示:
模式的實現(xiàn)觀察者模式的實現(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();
}
}
//抽象目標
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(); //通知觀察者方法
}
//具體目標
public class ConcreteSubject : Subject
{
public override void NotifyObserver()
{
Console.WriteLine("具體目標發(fā)生改變...");
Console.WriteLine("--------------");
foreach (var obs in observers)
{
obs.Response();
}
}
}
//抽象觀察者
public interface IObserver
{
void Response(); //反應
}
//具體觀察者1
public class ConcreteObserver1 : IObserver
{
public void Response()
{
Console.WriteLine("具體觀察者1作出反應!");
}
}
//具體觀察者1
public class ConcreteObserver2 : IObserver
{
public void Response()
{
Console.WriteLine("具體觀察者2作出反應!");
}
}程序運行結果如下: 具體目標發(fā)生改變... -------------- 具體觀察者1作出反應! 具體觀察者2作出反應! 應用場景通過前面的分析與應用實例可知觀察者模式適合以下幾種情形:
擴展:.net中的IObservable和 IObserver接口在.net環(huán)境下,其運行時庫為開發(fā)者提供了IObservable和 IObserver接口,用于實現(xiàn)觀察者模式軟件設計。另外,ObservableCollection 類表示一個動態(tài)數(shù)據(jù)集合,它可在添加、刪除項目或刷新整個列表時提供通知。
注:在 Java 中,通過 java.util.Observable 類和 java.util.Observer 接口定義了觀察者模式,只要實現(xiàn)它們的子類就可以編寫觀察者模式實例。 下面的示例演示觀察者設計模式,實現(xiàn)定位系統(tǒng)實時通知當前經(jīng)緯度坐標,代碼如下: class Program
{
static void Main(string[] args)
{
// 定義一個提供者和兩個觀察者
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>
/// 位置報告者:提供 IObserver<T> 實現(xiàn),它顯示有關當前控制臺位置的信息
/// </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 的調用返回的 IDisposable 實現(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}: 當前位置是 {0}, {1}", value.Latitude, value.Longitude, this.Name);
}
/// <summary>
/// 退訂:使類可以通過調用提供程序的 Dispose 實現(xiàn)來取消訂閱通知
/// </summary>
public virtual void Unsubscribe()
{
unsubscriber.Dispose();
}
}
/// <summary>
/// 位置跟蹤器:提供 IObservable<T> 實現(xiàn)
/// </summary>
public class LocationTracker : IObservable<Location>
{
public LocationTracker()
{
observers = new List<IObserver<Location>>();
}
private List<IObserver<Location>> observers;
/// <summary>
/// 訂閱:某觀察程序將要接收通知
/// </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 實現(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()
{ }
}程序運行結果如下: FixedGPS:當前位置是47.6456,-122.1312 MobileGPS:當前位置是47.6456,-122.1312 MobileGPS:當前位置是47.6677,-122.1199 MobileGPS:無法確定位置位置 跟蹤器已將數(shù)據(jù)傳輸?shù)組obileGPS |
|
|