转载:http://www.linxh.blog.chinaunix.net/uid-29140694-id-4123507.html
http://blog.csdn.net/xu__cg/article/details/53242995
观察者模式:定义了一个一对多的依赖关系,让一个或多个观察者对象监控一个主题对象。这样当一个主题对象状态发生变化时能够通知所有的依赖于此对象的那些观察者对象,使这些观察者对象能够自动更新。
类似场景
(1)聊天室程序的创建。服务器创建好后,A、B、C三个客户端连接好公开聊天。A向服务器发送数据,服务器在将数据分别发送给其他在线客户。也就是说,每个客户端需要更新服务器端的数据。
(2)网站上,很多人订阅了“Java主题”的新闻。当有这个主题新闻时,就会将这些新闻发给所有订阅的人。
(3)大家在玩CS游戏时,服务器需要将每个人的方位变化发给所有的客户。
上面这些场景,我们都可以使用观察者模式来处理。我们可以把多个订阅者、客户称之为观察者;需要同步给多个订阅者的数据封装到对对象中,称之为目标。
模式结构
(1)抽象主题角色(Subject):把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
(2)具体主题角色(ConcreteSubject):在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。
(3)抽象观察者角色(Observer):为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
(4)具体观察者角色(ConcreteObserver):该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。
package observer;
import java.util.ArrayList;
import java.util.List;
/**
* 观察者模式(Observer)
* 包括:
* 主题接口
* 具体主题类
* 观察者接口
* 具体观察者类
*
*/
//观察者接口:Observer
interface Observer {
public void update(Subject subject);
}
//抽象主题接口:Subject
interface Subject {
public void addObserver(Observer observer);
public void removeObserver(Observer observer);
public void notifyAllObserver();
}
//具体的主题类:ConcreteSubject
class ConcreteSubject implements Subject {
//主题中被所有观察者监控的状态
private String state;
//维护一个观察者列表
private List<Observer> list = new ArrayList<>();
public String getState() {
return state;
}
public void setState(String state) {
System.out.println("=====主题的状态发生了改变!=====");
this.state = state;
}
@Override
public void addObserver(Observer observer) {
list.add(observer);
}
@Override
public void removeObserver(Observer observer) {
list.remove(observer);
}
@Override
public void notifyAllObserver() {
for (Observer observer : list) {
observer.update(this);
}
}
}
//具体的观察者类:ConcreteObserver
class ConcreteObserver implements Observer {
//每个观察者对象的状态,需要和主题对象的状态保持同步更新
private String observerState;
@Override
public void update(Subject subject) {
//获取主题的状态
String subjectState = ((ConcreteSubject)subject).getState();
//更新观察者的状态
this.observerState = subjectState;
System.out.println("主题的状态:" + subjectState +
", 本观察者的状态:" + this.observerState);
}
}
public class ObserverTest {
public static void main(String[] args) {
//主题对象
ConcreteSubject subject = new ConcreteSubject();
//观察者
ConcreteObserver observer1 = new ConcreteObserver();
ConcreteObserver observer2 = new ConcreteObserver();
ConcreteObserver observer3 = new ConcreteObserver();
//注册
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.addObserver(observer3);
//改变主题状态
subject.setState("state1");
subject.notifyAllObserver();
subject.setState("state2");
subject.notifyAllObserver();
}
}
(1)它把观察者与被观察者分离,并将二者间的关系通过抽象观察者和抽象被观察者联系在一起,当一方发生变化时不会影响另一方的执行,从而降低了程序的耦合。
(2)可以支持多种不同的具体观察者实现,有利于程序的扩展。
(3)观察者的数目是可变的,主题可以实现动态的增加或移除观察者对象。
(4)被观察者在自身状态发生变化时,会主动通知观察者,如果不是被观察者主动通知,那就需要观察者通过定时任务的方式来监控被观察者的状态是否发生变化,被观察者主动通知的方式要比观察者定时监控方式性能更高。
观察者模式的缺点:
观察者模式是一种常用的触发机制,它形成一条触发链,依次对各个观察者的方法进行处理。但同时,这也算是观察者模式一个缺点,由于是链式触发,当观察者比较多的时候,性能问题是比较令人担忧的。并且,在链式结构中,比较容易出现循环引用的错误,造成系统假死。