1.观察者模式两种模式
(1)推模型:目标对象主动向观察者推送目标的详细信息 ; 推送的信息通常是目标信息的全部或部分信息
(2)拉模型:目标对象在通知观察者的时候,只传递少量信息 ;如果观察者需要更具体的信息,由观察者主动到目标对象中获取,相当于是观察者从目标对象中拉数据;一般这种模型的实现中,会把目标对象自身通过update方法传递给观察者。
比较
推模型是假定目标对象知道观察着需要的数据
拉模型是目标对象不知道观察着具体需要什么数据,因此把自身传给观察者,由观察者来取值
2.
观察者模式的优点:
(1)观察者模式实现了观察者和目标之间的抽象耦合
(2)观察者模式实现了动态联动
(2)观察者模式支持广播通信
3.
观察者模式的缺点:
(1)可能会引起无谓的操作
4.建议在以下情况下使用观察者模式
(1)当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化
(2)如果在更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该 有多少对象需要被连带改变
(3) 当一个对象必须通知其他的对象,但是你又希望这个对象和其他的被通知的对象是松散耦合的
例1: 拉模型
package observer_pull;
import java.util.ArrayList;
import java.util.List;
/**
* 观察者模式
* 抽象目标对象,它知道观察它的观察者,并提供添加和删除观察者的接口
* */
public class Subject {
//用来保存观察者
private List<Observer> observers = new ArrayList<Observer>();
/**
* 添加观察者
* */
public void add(Observer observer)
{
observers.add(observer);
}
/**
* 删除观察者
* */
public void remove(Observer observer)
{
observers.remove(observer);
}
/**
*向所有观察者发送消息
* */
public void notifyObservers(String content)
{
for(Observer observer : observers)
{
observer.update(content);
}
}
}
package observer_pull;
/**
* 观察者模式
* 观察者接口
* */
public interface Observer {
public void update(String state);
}
package observer_pull;
/**
* 观察者模式
* 具体目标对象 ,负责将有关状态存入到对应观察者对象中
* */
public class ConcreteSubject extends Subject {
//被观察对象的状态
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
this.notifyObservers(state);
}
}
package observer_pull;
/**
* 观察者模式
* 具体观察者对象
* */
public class ConcreteObserver implements Observer{
//观察者状态
private String observerState;
public ConcreteObserver(String observerState) {
super();
this.observerState = observerState;
}
@Override
public void update(String state) {
// TODO Auto-generated method stub
System.out.println(observerState+":"+state);
}
}
package observer_pull;
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver("观察者a");
ConcreteObserver observer2 = new ConcreteObserver("观察者b");
subject.add(observer1);
subject.add(observer2);
subject.setState("123");
}
}
输出结果:
观察者a:123
观察者b:123
例2 : 推模型
package observer_push;
import java.util.ArrayList;
import java.util.List;
/**
* 观察者模式
* 抽象目标对象,它知道观察它的观察者,并提供添加和删除观察者的接口
* */
public class Subject {
//用来保存观察者
private List<Observer> observers = new ArrayList<Observer>();
/**
* 添加观察者
* */
public void add(Observer observer)
{
observers.add(observer);
}
/**
* 删除观察者
* */
public void remove(Observer observer)
{
observers.remove(observer);
}
/**
*向所有观察者发送消息
* */
public void notifyObservers()
{
for(Observer observer : observers)
{
observer.update(this);
}
}
}
package observer_push;
/**
* 观察者模式
* 观察者接口
* */
public interface Observer {
public void update(Subject subject);
}
package observer_push;
/**
* 观察者模式
* 具体目标对象 ,负责将有关状态存入到对应观察者对象中
* */
public class ConcreteSubject extends Subject {
//被观察对象的状态
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
this.notifyObservers();
}
}
package observer_push;
/**
* 观察者模式
* 具体观察者对象
* */
public class ConcreteObserver implements Observer{
//观察者状态
private String observerState;
public ConcreteObserver(String observerState) {
super();
this.observerState = observerState;
}
@Override
public void update(Subject subject) {
// TODO Auto-generated method stub
System.out.println(observerState+":"+((ConcreteSubject)subject).getState());
}
}
package observer_push;
import java.util.Observer;
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver("观察者1");
ConcreteObserver observer2 = new ConcreteObserver("观察者2");
subject.add(observer1);
subject.add(observer2);
subject.setState("123");
}
}
输出结果:
观察者1:123
观察者2:123
例3: jdk实现package observer_jdk;
import java.util.Observable;
/**
* 目标对象
* */
public class ConcreteSubject extends Observable {
private String content ;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
//调用notifyObservers之前必须调用
this.setChanged();
//通知所有的观察者
this.notifyObservers(content);
}
}
</pre><p></p><pre name="code" class="java">package observer_jdk;
import java.util.Observable;
import java.util.Observer;
public class ConcreteObserver implements Observer {
private String state;
public ConcreteObserver(String state) {
super();
this.state = state;
}
@Override
public void update(Observable o, Object arg) {
// TODO Auto-generated method stub
System.out.println(state+" 通过拉模式获得内容:"+((ConcreteSubject)o).getContent());
System.out.println(state+" 通过推模式获得内容:"+arg);
}
}
package observer_jdk;
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver("观察者A");
ConcreteObserver observer2 = new ConcreteObserver("观察者B");
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.setContent("我变化了1");
subject.setContent("我变化了2");
}
}
输出结果:
观察者B 通过拉模式获得内容:我变化了1
观察者B 通过推模式获得内容:我变化了1
观察者A 通过拉模式获得内容:我变化了1
观察者A 通过推模式获得内容:我变化了1
观察者B 通过拉模式获得内容:我变化了2
观察者B 通过推模式获得内容:我变化了2
观察者A 通过拉模式获得内容:我变化了2
观察者A 通过推模式获得内容:我变化了2
此外,还可以在观察者observer中加入主题subject的引用,这样,在观察者需要取消注册subject时会更方便。