通俗的理解一下观察者模式:当一个受观察对象发生改变时,则观察它的所有对象都跟着更新。应用场景如,天气信息改变时,各种显示设备都跟着更新。
主要类包括:主题接口(被观察者接口)、主题类、观察者接口、观察者类。
过程中,主题(被观察者)可以采用push数据方式让观察者更新,观察者也可以采用pull数据方式更新,主要看数据的安全性问题,以及各观察者需要的数据情况。
观察者模式可以自己单独实现,也可以采用java.util.Observer接口(观察者)和java.util.Observable类(主题,被观察者)来实现,但是后者在更新个观察者时,是不分先后顺序的,而自己实现的时候可以控制这个更新顺序。
下面分别实验两种情况:
首先是自己实现,
1,下面是主题接口
2,下面是观察者接口
3,下面是其他的一些接口,主要是观察者类实现的时候用
4,下面是主题的实现类,即一个被观察类
5,下面是其中一个观察者
6,下面是另一个观察者
7,测试一下
整个过程很简单,扩展性很好。
上面的程序采用的是push的方式,如果想采用pull的方式,首先将观察者update方法参数改成主题接口类型,然后将主题类属性修改为public标识,之后就可以在update中强制转化类型并pull数据了。
下面是java.util.包中提供的观察者模式,需要说明的是,Observable(主题,被观察者)是一个类,而不是接口。
1,首先写一个具体的主题(被观察者),继承Observable类
2,其中一个观察者
3,另一个观察者
4,测试一下
主要类包括:主题接口(被观察者接口)、主题类、观察者接口、观察者类。
过程中,主题(被观察者)可以采用push数据方式让观察者更新,观察者也可以采用pull数据方式更新,主要看数据的安全性问题,以及各观察者需要的数据情况。
观察者模式可以自己单独实现,也可以采用java.util.Observer接口(观察者)和java.util.Observable类(主题,被观察者)来实现,但是后者在更新个观察者时,是不分先后顺序的,而自己实现的时候可以控制这个更新顺序。
下面分别实验两种情况:
首先是自己实现,
1,下面是主题接口
package net.roky.pattern.observer.self;
public interface Subject {
//注册增加观察者
public void addObserver(Observer o);
//删除观察者
public void delObserver(Observer o);
//修改通知观察者
public void notifyObservers();
}
2,下面是观察者接口
package net.roky.pattern.observer.self;
public interface Observer {
//观察者更新
public void update(int d1, String d2);
}
3,下面是其他的一些接口,主要是观察者类实现的时候用
package net.roky.pattern.observer.self;
public interface Display {
//屏显
public void display();
}
4,下面是主题的实现类,即一个被观察类
package net.roky.pattern.observer.self;
import java.util.ArrayList;
public class ConcreteSubject implements Subject {
ArrayList<Observer> arrayList;
private int data1;
private String data2;
ConcreteSubject(){
arrayList = new ArrayList<Observer>();
}
public void setElements(int d1, String d2){
this.data1 = d1;
this.data2 = d2;
this.notifyObservers();
}
public int getData1(){
return this.data1;
}
public String getData2(){
return this.data2;
}
public void addObserver(Observer o) {
// TODO 自动生成方法存根
this.arrayList.add(o);
}
public void delObserver(Observer o) {
// TODO 自动生成方法存根
int i = this.arrayList.indexOf(o);
if(i>=0){
this.arrayList.remove(i);
}
}
public void notifyObservers() {
// TODO 自动生成方法存根
for(Observer o : this.arrayList){
o.update(this.data1, this.data2);
}
}
}
5,下面是其中一个观察者
package net.roky.pattern.observer.self;
public class O1 implements Observer, Display {
private int data1;
private String data2;
O1(Subject subject){
subject.addObserver(this);
}
public void update(int d1, String d2) {
// TODO 自动生成方法存根
this.data1 = d1;
this.data2 = d2;
this.display();
}
public void display() {
// TODO 自动生成方法存根
System.out.println("new data:" + " data1:" + data1 + " data2:" + data2);
}
}
6,下面是另一个观察者
package net.roky.pattern.observer.self;
public class O2 implements Observer, Display {
private int data1;
O2(Subject subject){
subject.addObserver(this);
}
public void update(int d1, String d2) {
// TODO 自动生成方法存根
this.data1 = d1;
this.display();
}
public void display() {
// TODO 自动生成方法存根
System.out.println("new data:" + " data1:" + data1);
}
}
7,测试一下
package net.roky.pattern.observer.self;
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO 自动生成方法存根
ConcreteSubject cs = new ConcreteSubject();
new O1(cs);
new O2(cs);
cs.setElements(10, "abcdefg");
cs.setElements(20, "hijklmn");
}
}
整个过程很简单,扩展性很好。
上面的程序采用的是push的方式,如果想采用pull的方式,首先将观察者update方法参数改成主题接口类型,然后将主题类属性修改为public标识,之后就可以在update中强制转化类型并pull数据了。
下面是java.util.包中提供的观察者模式,需要说明的是,Observable(主题,被观察者)是一个类,而不是接口。
1,首先写一个具体的主题(被观察者),继承Observable类
package net.roky.pattern.observer;
import java.util.Observable;
public class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
WeatherData(){
}
public float getTemperature(){
return this.temperature;
}
public float getHumidity(){
return this.humidity;
}
public float getPressure(){
return this.pressure;
}
public void measurementsChanged(){
super.setChanged();
super.notifyObservers();
}
public void setMeasurements(float t, float h, float p){
this.temperature = t;
this.humidity = h;
this.pressure = p;
this.measurementsChanged();
}
}
2,其中一个观察者
package net.roky.pattern.observer;
import java.util.Observable;
import java.util.Observer;
public class Display1 implements Observer {
//Observable observeable;
private float temperature;
private float humidity;
Display1(Observable observable){
observable.addObserver(this);
}
public void update(Observable arg0, Object arg1) {
if(arg0 instanceof WeatherData){
WeatherData weatherData = (WeatherData) arg0;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
this.display();
}
}
public void display(){
System.out.println("display1,"+ " temperature:" + this.temperature + " ,humidity:" + this.humidity);
}
}
3,另一个观察者
package net.roky.pattern.observer;
import java.util.Observable;
import java.util.Observer;
public class Display2 implements Observer {
// Observable observeable;
private float temperature;
private float humidity;
private float pressure;
Display2(Observable observable) {
observable.addObserver(this);
}
public void update(Observable arg0, Object arg1) {
if (arg0 instanceof WeatherData) {
WeatherData weatherData = (WeatherData) arg0;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
this.pressure = weatherData.getPressure();
this.display();
}
}
public void display() {
System.out.println("display2," + " temperature:" + this.temperature
+ " ,humidity:" + this.humidity + " ,pressure:" + this.pressure);
}
}
4,测试一下
package net.roky.pattern.observer;
public class Main {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
new Display1(weatherData);
new Display2(weatherData);
for (int i = 1; i < 1000; i++) {
weatherData.setMeasurements(i % 100, 2 * i, 25.3f);
}
}
}