不知道大家有没有听说过观察者模式,有人也叫发布-订阅模式,我们先来看一个案例,案例如下:一个公司有前台人员,和后台开发人员,公司老板回来的时候会先经过前台然后才来到后台开发这边,工作压力大,后台开发人员偶尔会偷偷懒,炒一下股或者看看NBA这些小工作,他们串通前台的人员,如果老板回来要先通知他们,好让他们有个准备。程序实现如下:
第一步:我们把前台人员称为通知者,我们抽象通知者,因为通知者可能是前台人员或者其他人,但是具有相同的行为,于是可以使用接口来规范行为。
//抽象通知者
public interface Subject {
//添加
public void attach(Observer observer);
//通知所有的观察者
public void notifyAllObserver();
}
第二步:前台人员是具体的通知者,实现接口Subject,有三个私有属性,姓名,自己的状态,以及需要通知的观察者,我们把后台开发人员称为观察者,他们可能在看NBA,或者看篮球等等。当老板回来的时候,通知者需要改变自己的状态,通知所有的观察者对象,当然通知者肯定有添加观察者的方法,就是添加需要通知的观察者,这里有两个具体的通知者,一个是前台人员,一个是老板,我们都不希望是老板来通知我们~~
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
//抽象通知者
public class Secretary implements Subject {
private String name; //姓名
private String action; //状态
private List<Observer> observers = new ArrayList<Observer>(); //观察者集合
//添加
public void attach(Observer observer) {
observers.add(observer);
}
//通知所有的观察者
public void notifyAllObserver() {
for (Iterator<Observer> iter=observers.iterator(); iter.hasNext();) {
Observer observer = iter.next();
observer.update();
}
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
//通知者
public class Boss implements Subject{
private String name; //姓名
private String action; //状态
private List<Observer> observers = new ArrayList<Observer>(); //观察者集合
//添加
public void attach(Observer observer) {
observers.add(observer);
}
//通知所有的观察者
public void notifyAllObserver() {
for (Iterator<Observer> iter=observers.iterator(); iter.hasNext();) {
Observer observer = iter.next();
observer.update();
}
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
第三步:抽象观察者,因为我们知道观察者有各种各样的,在做什么事情,我们都不知道,但是老板回来,我们就需要通知他们。
于是我使用抽象类来定义,而不使用接口,因为抽象类可以有属性,即是状态数据字段,定义一个抽象的方法,就是更新自己的状态,也有一个通知者的引用,进而和通知者联系。
//抽象观察者
public abstract class Observer {
protected String name; //姓名
protected Secretary secretary; //通知者
//constructor
public Observer(String name, Secretary secretary) {
this.name = name;
this.secretary = secretary;
}
//更新状态
public abstract void update();
}
第四步:我们来两个具体的观察者,一个在看NBA,一个在炒股。
//NBA观察者
public class NBAObserver extends Observer{
public NBAObserver(String name, Secretary secretary) {
super(name, secretary);
}
//更新状态
public void update() {
System.out.println(secretary.getAction() + " " + this.name + "不要看篮球了,继续工作。");
}
}
//股票观察者
public class StockObserver extends Observer{
public StockObserver(String name, Secretary secretary) {
super(name, secretary);
}
//更新状态
public void update() {
System.out.println(secretary.getAction() + " " + this.name + "关闭股票行情,继续工作。");
}
}
第五步:接下来就是测试一下了。我们定义一个通知者、两个观察者,通知者是老板,老板回来的时候通知我们的两个观察者,很糟糕哦~~
//测试
/**
* 分析:我们使用继承与多态的方式重构了程序,抽象了观察者和通知者,因为观察者可能是在看NBA,
* 也可能在看股票或者其他,而通知者也一样,可能是老板,也可能是是我们上司,但是通知者具有相
* 同的行为,于是可以使用接口来定义抽象,使用依赖倒置的原则,可以使得程序的可拓展性大大提高
* ,代码的可重用性也提高。
*/
public class Test2 {
public static void main(String[] args) {
Secretary boss = new Secretary(); //通知者
Observer xiaowang = new StockObserver("小王", boss); //股票玩家
Observer xiaodong = new NBAObserver("小东", boss); //股票玩家
//通知者记录
boss.attach(xiaowang);
boss.attach(xiaodong);
//通知者状态发生改变
boss.setAction("老板我回来了!");
//通知所有的观察者即股票玩家
boss.notifyAllObserver();
}
}
总结:
观察者模式也叫发布-订阅模式。定义:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象 。这个主题对象在状态发生变化的时,会通知所有的观察者对象,使它们能够自动的更新自己。
遵循的原则:依赖倒置的原则、里氏替换原则。
特点:将一个系统分隔成一系列相互协作的类有一个很不好的副作用,那就是需要维护相互对象将的一致性,我们不希望为了维护一致性而是各类紧密相连,这样会给维护、扩展和重用都带来不便。
使用场景:1.当一个对象改变时需要同时改变其他对象的时候。(不需要知道具体需要改变的对象)