老板回来我不知道 观察者模式
14.1 老板回来?我不知道!
14.2 双向耦合的代码
namespace 观察者模式 { class Program { static void Main(string[] args) { //前台小姐童子喆, Secretary tongzizhe = new Secretary(); //看股票的同事, StockObserver tongshi1 = new StockObserver("魏关姹", tongzizhe); StockObserver tongshi2 = new StockObserver("易管查", tongzizhe); //前台记下了两位同事, tongzizhe.Attach(tongshi1); tongzizhe.Attach(tongshi2); //发现老板回来, tongzizhe.SecretaryAction = "老板回来了!"; //通知两个同事, tongzizhe.Notify(); Console.Read(); } } //前台秘书类, class Secretary { //同事列表, private IList<StockObserver> observers = new List<StockObserver>(); private string action; //增加, //有几个同事请前台帮忙,就给集合增加几个对象, public void Attach(StockObserver observer) { observers.Add(observer); } //通知, //待老板来时,就给所有请帮忙的同事发通知, public void Notify() { foreach (StockObserver o in observers) o.Update(); } //前台状态, //前台通过电话,所说的话或所做的事, public string SecretaryAction { get { return action; } set { action = value; } } } //看股票的同事类, class StockObserver { private string name; private Secretary sub; public StockObserver(string name, Secretary sub) { this.name = name; this.sub = sub; } //得到前台通知,赶快采取行动, public void Update() { Console.WriteLine("{0} {1} 关闭股票行情,继续工作!", sub.SecretaryAction, name); } } }
14.3 解耦实践一
namespace 观察者模式 { class Program { static void Main(string[] args) { //前台小姐童子喆, Secretary tongzizhe = new Secretary(); //看股票的同事, StockObserver tongshi1 = new StockObserver("魏关姹", tongzizhe); //看NBA的同事, NBAObserver tongshi2 = new NBAObserver("易管查", tongzizhe); //前台记下了两位同事, tongzizhe.Attach(tongshi1); tongzizhe.Attach(tongshi2); //发现老板回来, tongzizhe.SecretaryAction = "老板回来了!"; //通知两个同事, tongzizhe.Notify(); Console.Read(); } } //前台秘书类, class Secretary { //同事列表, private IList<Observer> observers = new List<Observer>(); private string action; //增加, public void Attach(Observer observer) //针对抽象编程,减少了与具体类的耦合, { observers.Add(observer); } //通知, public void Notify() { foreach (Observer o in observers) o.Update(); } //前台状态, public string SecretaryAction { get { return action; } set { action = value; } } } //抽象观察者, abstract class Observer { protected string name; protected Secretary sub; public Observer(string name, Secretary sub) { this.name = name; this.sub = sub; } public abstract void Update(); //让两个观察者即同事继承抽象观察者,重写Update方法, } //看股票的同事, class StockObserver : Observer { public StockObserver(string name, Secretary sub) : base(name, sub) { } public override void Update() { Console.WriteLine("{0} {1} 关闭股票行情,继续工作!", sub.SecretaryAction, name); } } //看NBA的同事, class NBAObserver : Observer { public NBAObserver(string name, Secretary sub) : base(name, sub) { } public override void Update() { Console.WriteLine("{0} {1} 关闭NBA直播,继续工作!", sub.SecretaryAction, name); } } }
14.4 解耦实践二
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); } } }
14.5 观察者模式
观察者模式又叫做发布/订阅模式,
它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己,
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(); } } //Subject类,可翻译为主题或抽象通知者,一般用一个抽象类或者一个接口实现, //它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任意数量的观察者, //抽象主题提供一个接口,可以增加和删除观察者对象, 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(); } } } //ConcreteSubject类,具体通知者类, //叫做具体主题或具体通知者,将有关状态存入具体观察者对象, //有具体主题的内部状态改变时,给所有登记过的观察者发出通知, //具体主题角色通常用一个具体子类实现, class ConcreteSubject : Subject { private string subjectState; //具体通知者状态 public string SubjectState { get { return subjectState; } set { subjectState = value; } } } //Observer类,抽象观察者,为所有的具体观察者定义一个接口, //在得到主题的通知时更新自己,这个接口叫做更新接口, //抽象观察者一般用一个抽象类或者一个接口实现, //更新接口通常包含一个Update()方法,这个方法叫做更新方法, abstract class Observer { public abstract void Update(); } //ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的更新接口, //以便使本身的状态与主题的状态相协调, //具体观察者角色可以保存一个指向具体主题对象的引用, //具体观察者角色通常用一个具体子类实现, 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; } } } }
14.6 观察者模式特点
观察者模式的动机是什么呢?
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性,我们不希望为了维持一致性而;使各类紧密耦合,这样会给维护,扩展和重用带来不便,观察者模式的关键对象是主题Subject和观察者Observer,一个Subject可以有任意数目的依赖它的Observer,一旦Subject的状态发生了改变,所有的Observer都可以得到通知,Subject发出通知时并不需要知道谁是它的观察者,也就是说,具体观察者是谁,它根本不需要知道,
什么时候使用观察者模式呢?
当一个对象的改变需要同时改变其它对象的时候,而且它不知道具体有多少对象待改变时,应考虑使用观察者模式,
观察者模式所做的工作其实就是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化,
抽象观察者时用的抽象类,也可以用接口,
14.7 观察者模式不足
抽象通知者还是依赖抽象观察者,也就是说,没有抽象观察者这样的接口,通知功能就完成不了了,另外就是每个具体观察者,它不一定是更新的方法要调用的阿,即根本不是同名方法,
14.8 事件委托事件
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; 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); } } }
14.9 事件委托说明
委托就是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为,委托方法的使用可以像其它任何方法一样,具有参数和返回值,委托可以看作是对方法的抽象,是方法的类,委托的实例将代表一个具体的方法,
一个委托可以搭载多个方法,所有方法被依次唤起,更重要的是,它可以使得委托对象所搭载的方法并不需要属于同一个类,解决了与抽象观察者的耦合问题,
委托使用前提,委托对象所搭载的所有方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值类型,
14.10 石守吉失手机后的委托