观察者模式(发布-订阅模式)
定义
定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
特点
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。
当一个对象的改变需要同时改变其他对象时,而且他不知道具体有多少对象需要改变时,应该考虑使用观察者模式。总的来说,观察者模式是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖的具体,从而使得各自的变化都不会影响另一边的变化。
UML图
用例
抽象通知者
interface Subject{
void attach(Observer observer);
void detach(Observer observer);
void notify();
public String getSubjectState();
public String setSubjectState();
}
具体通知者:可能是前台,可能是老板,它们各自有方法,但对于抽象通知者来说都一样,所以它们都实现这个接口。
class Boss implements Subject{
//同事列表
private List<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(){
for(v : observers)
v.uodate();
}
//老板状态
public String getSubjectState(){
return action;
};
public String setSubjectState(String action){
this.action = action;
};
}
抽象观察者
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 extends Observer{
@Override
public void update(){
System.out.printlv(sub.getSubjectState + name + "老板来了,关闭股市行情,继续工作。");
}
}
客户端代码
Boss huahansan = new Boss();
//看股票的同事
StockObserver so = new StockObserver ("小明",huhansan);
//看NBA的同事
NBAObserver no = new NBAObserver ("小红",huhansan);
huhansan.attach(so);
huhansan.attach(no);
huhansan.setSubjectState("我胡汉三又回来了!");
huhansan.notify();
此例的不足
- 抽象通知者依赖抽象观察者,如果没有抽象观察者这样的接口,通知者就无法通知了。
- 每个具体观察者不一定都要用notify方法。
用例(改进)
事件委托实现:
委托就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看做函数的抽象,是函数的类,委托的实例代表一个具体的函数。
一个委托可以搭载多个方法,所有方法被依次唤起,重要的是委托对象搭载的方法并不需要来自同一个类。但是委托对象搭载的所有方法必须具有相同的原形和形式,即拥有相同的参数列表和返回值类型。
去掉抽象观察类,为具体观察者类添加各自合适的方法。
class StockObserver{
protected String name;
protected Subject sub;
public StockObserver(String name, Subject sub){
this.name = name;
this.sub = sub;
}
//关闭股市行情
public void closeStockMarket(){
System.out.printlv(sub.getSubjectState + name + "老板来了,关闭股市行情,继续工作。");
}
}
class NBAObserver{
protected String name;
protected Subject sub;
public NBAObserver(String name, Subject sub){
this.name = name;
this.sub = sub;
}
//关闭NBA直播
public void closeNBADirectSeeding(){
System.out.printlv(sub.getSubjectState + name + "老板来了,关闭NBA直播,继续工作。");
}
}
抽象通知者:由于不想依赖于抽象观察者,所以不需要“增加”和“减少”方法。
interface Subject{
void notify();
public String getSubjectState();
public String setSubjectState();
}
具体通知类:声明委托完成通知
public delegate void EventHandler();//无参数,无返回值
//老板类 前台秘书类类似,略
class Boss extends Subject{
private String action;
//声明一个事件event,类型为委托
public event EventHandler update;
public void notify(){
update();
}
//老板状态
public String getSubjectState(){
return action;
};
public String setSubjectState(String action){
this.action = action;
};
}
客户端:决定通知谁
Boss huahansan = new Boss();
//看股票的同事
StockObserver so = new StockObserver ("小明",huhansan);
//看NBA的同事
NBAObserver no = new NBAObserver ("小红",huhansan);
//老板的状态更新导致新增通知事件给看股票的或者看NBA直播的
huhansan.update += new EventHandler(so.closeStockMarket());
huhansan.update += new EventHandler(no.closeNBADirectSeeding());
huhansan.setSubjectState("我胡汉三又回来了!");
huhansan.notify();