第14章 老板回来,我不知道--观察模式
14.1 老板回来?我不知道!
14.2 双向耦合代码
class Secretary
{
//同事列表
private IList
private string action;
//增加
public void Attach(StockObserver observer)
{
observer.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);
}
}
客户端程序如下
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();
}
观察上面的代码可以发现,前台类和同事之间相互耦合。
14.3 解耦实践一
//抽象的观察者
abstract class Observer
{
protect string name;
protected Secretary sub;
public Observer(string name,Secretary sub)
{
this.name = name;
this.sub = sub;
}
public abstract void 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);
}
}
//前台秘书类
class Secretary
{
//同事列表
private IList
private string action;
//增加,针对抽象结成,减少了与具体类的耦合
public void Attach(Observer observer)
{
observer.Add(observer);
}
//减少,针对抽象结成,减少了与具体类的耦合
public void Detach(Observer observer)
{
observers.Remove(observer);
}
//通知
public void Notify()
{
foreach(observer o in observers)
{
o.Update();
}
}
//前台状态
public string SecretaryAction
{
get{ return action; }
set{ action = value;}
}
}
14.4 解耦实践二
//通知者接口
interface Subject
{
void Attach(Observer observer);
void Detach(Observer observer);
void Notify();
string SubjectState
{
get;
set;
}
}
//老板类
class Boss : Subject
{
//同事列表
private IList
private string action;
//增加
public void Attach(Observer observer)
{
observer.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.EriteLine(“{0} {1} 关闭股票行情,继续工作”,sub.SubjiectState,name);
}
}
客户端代码
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();
14.5 观察者模式
观察者模式 定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,是他们能够自动更新自己。
Subject类,可翻译为主题或抽象通知者,被观察者:
abstract class Subject
{
private IList
//增加观察者
public void Attach(Observer observer)
{
observers.Add(observer);
}
//移除观察者
public void Detch(Observer observer)
{
observers.Remove(observer);
}
//通知
public void Notify()
{
foreach(Observer o in observers)
{
o.Update();
}
}
}
Observer类,抽象观察者
abstract class Observer
{
public abstract void Update();
}
ConcreteSubject类:具体主题类或具体通知者
class ConcreteSubject : Subject
{
private string subjectState;
//具体被观察者状态
public string SubjectState
{
get { return subjectState; }
set { subjectState = value;}
}
}
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;}
}
}
客户端代码
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 = “AEC”;
s.Notify();
Console.Read();
}
14.6 观察者模式特点
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维护一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。
当一个对象改变需要同时更改其他对象时,而且他不知道具体多少对象有待改变时,应该考虑使用观察者模式。
观察者模式所做的工作其实就是接触耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使的各自的变化都不会影响到另一边的变化。
14.7 观察者的不足
观察者模式中,观察者类还是依赖于抽象的Update接口,被观察者也是通过操作此接口达到目的。如果某些观察者是系统已经实现好的类怎么办。
如果观察者与被观察者之间互不相识怎么办。
14.8 事件委托实现
“看股票观察者“类和”看NBA观察者“类,去掉了父类”抽象观察者“,所以补上一些代码,并将”更新“方法更改为各自适合的方法名。
//看股票的同事
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}关闭股票行情、继续工作”, name, sub.SubjectState);
}
}
//看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直播”, name, sub.SubjectState);
}
}
现实中就是这样的,方法名就不一定相同
//通知者接口
interface Subject
{
void Notify();
string SubjectState
{
get;
set;
}
}
声明一个委托,名称叫“EventHandler”,无参数,无返回值。
delegate void EventHandler();
“老板“类和”前台秘书“类
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 Secretary : Subject
{
//老板类类似,略高
}
//客户端代码
//老板胡汉三
Boss huhansan = new Boss();
//看股票的同事
StockObserver tongshi1 = new StockObserver(“未关严”,huhansan);
//看NBA的同事
NBAObserver tongshi2 = new NBAObserver(“善观察”,huhansan);
huhansan.Update += new EventHandle(tongshi1.CloseStockMarket);
huhansan.Update += new EventHandler(tongshi2.CloseNBADirectSeeding);
//老板回来
huhansan.SubjectState = “我胡汉三回来了”;
//发出通知
huhansan.Notfy();
14.9 事件委托说明
Windows的技术,委托相当于函数的抽象,但是其搭载的函数,必须具有相同的参数和返回值。还是没有OC的动态运行时技术强大。