观察者模式定义了一种一对多的依赖关系,让多个观察者同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
基本代码: 观察者模式
Subject类:可翻译为主题或者抽象通知者。一般用一个抽象类或者一个接口实现。它把所有观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
Observer类:抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包含一个Update()方法,这个方法叫做更新方法。
ConcreteSubject类: 叫做具体主题或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
ConcreteObserver类: 具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。具体观察者角色可以保存一个指向具体主题对象的引用。
using System;
using System.Collections.Generic;
using System.Text;
namespace 观察者模式
{
class Program
{
static void Main(string[] args)
{
ConcreteSubject s = new ConcreteSubject();//具体主题
//将具体观察者添加到主题的 观察者列表
s.Attach(new ConcreteObserver(s, "X"));
s.Attach(new ConcreteObserver(s, "Y"));
s.Attach(new ConcreteObserver(s, "Z"));
//主题状态
s.SubjectState = "ABC";
s.Notify();
Console.Read();
}
}
//抽象主题
abstract class Subject
{
private IList<Observer> observers = new List<Observer>();//观察者列表
//增加观察者
public void Attach(Observer observer)
{
observers.Add(observer);
}
//移除观察者
public void Detach(Observer observer)
{
observers.Remove(observer);
}
//通知
public void Notify()
{
foreach (Observer o in observers)
{
o.Update();
}
}
}
//具体通知者 具体主题
class ConcreteSubject : Subject
{
private string subjectState;
//具体通知者状态
public string SubjectState
{
get { return subjectState; }
set { subjectState = value; }
}
}
//抽象观察者
abstract class Observer
{
public abstract void Update();
}
//具体观察者
class ConcreteObserver : Observer
{
private string name;
private string observerState;//观察者的主题状态
private ConcreteSubject subject;//具体主题
public ConcreteObserver(
ConcreteSubject subject, string name)
{
this.subject = subject;
this.name = name;
}
//更新
public override void Update()
{
observerState = subject.SubjectState;
Console.WriteLine("观察者{0}的新状态是{1}",
name, observerState);
}
public ConcreteSubject Subject
{
get { return subject; }
set { subject = value; }
}
}
}
老板回来了,我不知道--观察者模式
using System;
using System.Collections.Generic;
using System.Text;
namespace 观察者模式
{
class Program
{
static void Main(string[] args)
{
//老板胡汉三
Boss huhansan = new Boss();
//看股票的同事
StockObserver tongshi1 = new StockObserver("魏关姹", huhansan);
//看NBA的同事
NBAObserver tongshi2 = new NBAObserver("易管查", huhansan);
huhansan.Attach(tongshi1);
huhansan.Attach(tongshi2);
huhansan.Detach(tongshi1);
//老板回来
huhansan.SubjectState = "我胡汉三回来了!";
//发出通知
huhansan.Notify();
Console.Read();
}
}
//通知者接口
interface Subject //主题/通知者 接口
{
void Attach(Observer observer);
void Detach(Observer observer);
void Notify();
string SubjectState
{
get;
set;
}
}
//秘书:具体主题或者具体通知者
class Secretary : Subject
{
//同事列表
private IList<Observer> observers = new List<Observer>();
private string action;//
//增加
public void Attach(Observer observer)
{
observers.Add(observer);
}
//减少
public void Detach(Observer observer)
{
observers.Remove(observer);
}
//通知
public void Notify()
{
foreach (Observer o in observers)
o.Update();
}
//前台状态
public string SubjectState
{
get { return action; }
set { action = value; }
}
}
//老板: 具体主题或者具体通知者
class Boss : Subject
{
//同事列表
private IList<Observer> observers = new List<Observer>();
private string action;
//增加
public void Attach(Observer observer)
{
observers.Add(observer);
}
//减少
public void Detach(Observer observer)
{
observers.Remove(observer);
}
//通知
public void Notify()
{
foreach (Observer o in observers)
o.Update();
}
//老板状态
public string SubjectState
{
get { return action; }
set { action = value; }
}
}
//抽象观察者 : 抽象同事
abstract class Observer
{
protected string name;
protected Subject sub;
public Observer(string name, Subject sub)
{
this.name = name;
this.sub = sub;
}
public abstract void Update(); // 观察者收到新的主题或者通知后处理方法
}
//看股票的同事
class StockObserver : Observer
{
public StockObserver(string name, Subject sub)
: base(name, sub)
{
}
public override void Update()
{
Console.WriteLine("{0} {1} 关闭股票行情,继续工作!", sub.SubjectState, name);
}
}
//看NBA的同事
class NBAObserver : Observer
{
public NBAObserver(string name, Subject sub)
: base(name, sub)
{
}
public override void Update()
{
Console.WriteLine("{0} {1} 关闭NBA直播,继续工作!", sub.SubjectState, name);
}
}
}
观察者模式的特点:
将一个系统分割成一系列相互协作的类有一个很好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。
而观察者模式的关键对象是主题Subject和观察者Observer,一个Subject可以由任意数目的依赖它的Observer,一旦Subject的状态发生改变,所有的Observer都可以得到通知。Subject发出通知时并不需要知道谁是它的观察者,也就是说具体观察者是谁,它根本不需知道。而任何一个具体观察者不知道也不需要知道其他观察者的存在。
什么时候考虑观察者模式呢?
当一个对象的改变需要同时改变其他对象的时候。而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。
观察者模式所做的工作其实就是在接触耦合,让耦合的双方都依赖于抽象。而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。
现实编程中,具体的观察者完全有可能是风牛马不相及的类,但它们都需要根据通知者的通知来做出Update()的操。
观察者模式的不足:
尽管当点击“运行”按钮时,确实是在通知相关的控件产生变化,但它们是不可能用接口的方式来实现观察者模式的。
抽象通知者 还是依赖于 抽象观察者,万一没有了抽象观察者这样的接口,我这通知的功能就玩不成了。
事件委托实现:
using System;
using System.Collections.Generic;
using System.Text;
namespace 观察者模式
{
class Program
{
static void Main(string[] args)
{
//老板胡汉三
Boss huhansan = new Boss();
//看股票的同事
StockObserver tongshi1 = new StockObserver("魏关姹", huhansan);
//看NBA的同事
NBAObserver tongshi2 = new NBAObserver("易管查", huhansan);
huhansan.Update += new EventHandler(tongshi1.CloseStockMarket);
huhansan.Update += new EventHandler(tongshi2.CloseNBADirectSeeding);
//老板回来
huhansan.SubjectState = "我胡汉三回来了!";
//发出通知
huhansan.Notify();
Console.Read();
}
}
//通知者接口
interface Subject
{
void Notify();
string SubjectState
{
get;
set;
}
}
//事件处理程序的委托
delegate void EventHandler();
//秘书: 具体的主题或者通知者
class Secretary : Subject
{
//声明一事件Update,类型为委托EventHandler
public event EventHandler Update;//秘书的更新事件
private string action;
//通知方法: 触发Update事件
public void Notify()
{
Update();
}
public string SubjectState
{
get { return action; }
set { action = value; }
}
}
//老板: 具体的主题或者通知者
class Boss : Subject
{
//声明一事件Update,类型为委托EventHandler
public event EventHandler Update;//老板的更新事件
private string action;
public void Notify()
{
Update();
}
//主题状态或者通知消息
public string SubjectState
{
get { return action; }
set { action = value; }
}
}
//看股票的同事
class StockObserver
{
private string name;
private Subject sub;//订阅的主题
public StockObserver(string name, Subject sub)
{
this.name = name;
this.sub = sub;
}
//关闭股票行情
public void CloseStockMarket()
{
Console.WriteLine("{0} {1} 关闭股票行情,继续工作!", sub.SubjectState, name);
}
}
//看NBA的同事
class NBAObserver
{
private string name;
private Subject sub;//订阅的主题
public NBAObserver(string name, Subject sub)
{
this.name = name;
this.sub = sub;
}
//关闭NBA直播
public void CloseNBADirectSeeding()
{
Console.WriteLine("{0} {1} 关闭NBA直播,继续工作!", sub.SubjectState, name);
}
}
}
事件委托说明:
委托就是一种引用方法的类型。一旦委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。。委托可以看做是对函数的抽象,是函数的“类”。委托的实例将代表一个具体的函数。
new EventHandler(tongshi1.CloseStockMarket) 其实就是一个委托的实例。而它就等于将 “tongshi1.CloseStockMarket”这个方法委托给“huhansan.Update”这个方法了。
一个委托可以搭载多个方法,所有方法被依次唤起。
可以使得委托所搭载的方法并不需要属于同一个类。
委托对象所搭载的所有方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值类型。
先有观察者模式,再有委托事件技术的。它们各有优缺点,可以看看MSDN。