观察者模式
观察者模式是对象行为型模式,它定义了一种一堆多的依赖关系,当一个对象的状态发生改变时,所有依赖于它对象都会得到通知。观察者模式也被成为发布-订阅模式。我们在使用微信的时候订阅公众号,在公众号有心得文章时会推送给订阅公众号的人,在使用微博时,关注了某博主,在我们刷微博同时博主有新的微博时会将新的消息展示给我,这两种案例都是使用了观察者模式。
观察者模式的适用性
-
观察者模式适用于当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在独立的对象中以使它们可以各自独立地改变和复用。
-
观察者模式适用于当改变一个对象时需要立刻改变其他的对象,但是在发生改变时不知道有多少个其他对象需要改变。
-
观察者模式适用于当必须通知其他对象但是其他对象只有在需要通知时才知道有哪些的情况下。
观察者模式的结构图
观察者模式总共有四类角色:
1、抽象主题角色(Subject):抽象主题角色保存了它的所有观察者,同时提供了增加、删除观察者,通知观察者观察对象已改变的方法。
2、具体主题角色(ConcreteSubject):具体主题角色提供了修改合查询状态的方法,同时在修改状态时通知观察者。
3、抽象观察者角色(Observer):为在目标改变时需获得通知的对象定义一个更新的接口。
4、具体观察者(ConcreteObserver):维护一个指向ConcreteSubject的引用,存储与目标对象一致的状态。
观察者模式示例
首先定义抽象主题角色
public class Subject { private Vector<Observer> vectors; public void attach(Observer observer) { this.vectors.add(observer); } public void detach(Observer observer) { this.vectors.remove(observer); } public void notifyObserver() { for (Observer observer : vectors) { observer.update(); } } }
具体主题角色,继承抽象主题角色实现具体的业务,这里只是提供状态的变更
public class ConcreteSubject extends Subject { public int state; public int getState() { return state; } public void setState() { this.state = state; notifyObserver(); } }
抽象观察者角色
public interface Observer { public void update(); }
具体观察者角色,保留了ConcreteSubject的引用,在update()方法被调用时,同步状态,这里我原本想改为在update(int state)方法时直接传递状态来解耦,但是由于update()方法为public的,如果其他对象调用了岂不是将state改为了不同的值,而不是观察所得的主题角色的状态。所以这里还是保留了ConcreteSubject的引用
public class ConcreteObserver implements Observer { public int observerState; private ConcreteSubject concreteSubject; public void setConcreteSubject(ConcreteSubject concreteSubject) { this.concreteSubject = concreteSubject; } @Override public void update() { if (concreteSubject==null){ System.out.println("观察者已经没有观察ConcreteSubject了"); }else { observerState=concreteSubject.state; System.out.println("观察者状态修改为"+observerState); } } }
客户端
public class Client { public static void main(String[] args) { /*主题角色*/ ConcreteSubject concreteSubject = new ConcreteSubject(); /*定义观察者角色*/ ConcreteObserver concreteObserver = new ConcreteObserver(); /* 设计观察者中的主题*/ concreteObserver.setConcreteSubject(concreteSubject); concreteSubject.attach(concreteObserver); concreteSubject.setState(1); concreteSubject.setState(2); } } /* 运行结果: 观察者状态修改为1 观察者状态修改为2*/
JDK提供的观察者模式的实现
首先JDK的java.util包中提供了Observable类和Observer接口,通过继承Observable类来实现主题角色,继承Observer接口来实现观察者角色。定义一个Wached对象继承Observable,声明一个state通过在改变state的值的时候来提醒观察者对象进行对应的修改。
public class Wached extends Observable { private String state=""; public String getState() { return state; } public void setState(String state) { if (!this.state.equals(state)){ this.state = state; setChanged(); } notifyObservers(); } }
观察者对象比较简单,实现update方法就行了
public class Wacher implements Observer { @Override public void update(Observable o, Object arg) { System.out.println("被观察者的状态改变成了"+((Wached)o).getState()); } }
客户端
public class Client { public static void main(String[] args) { /*创建被观察者*/ Wached wached = new Wached(); /*创建观察者*/ Wacher wacher = new Wacher(); /*在被观察者对象中登记观察者*/ wached.addObserver(wacher); wached.setState("1"); wached.setState("2"); } } /* 运行结果: 被观察者的状态改变成了1 被观察者的状态改变成了2*/
观察者模式的优点
1、观察者模式能够去除重复的代码,使得代码易读便于扩展。
2、解耦,在需要新增一个观察者的时候只需要new一个出来,然后注册到主题对象就可以了,在观察者不需要观察该主题对象,只需要在主题对象的观察者列表中去除该观察者对象即可。