《head first》学习札记之二——观察者模式
《head first》学习笔记之二——观察者模式
通俗的理解一下观察者模式:当一个受观察对象发生改变时,则观察它的所有对象都跟着更新。应用场景如,天气信息改变时,各种显示设备都跟着更新。
主要类包括:主题接口(被观察者接口)、主题类、观察者接口、观察者类。
过程中,主题(被观察者)可以采用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); } } }