您的位置:首页 > 其它

23种设计模式之-----观察者模式(Observer Pattern)

2018-01-02 19:51 549 查看
进入正题之前,我给对于设计模式来说还是新手的同学推荐一本学习设计模式的书,这本书叫做《Head First设计模式》,如果可能的话,看英文原版能让你更加贴近于作者的思想。

进入正题,这次我学习的是观察者模式(Observer Pattern),在java语言中用得最多的设计模式之一。

观察者模式,又叫发布-订阅模式,具体的定义是:定义了对象之间一对多的依赖,当一个对象的状态改变时,它的所有依赖者都将受到通知并进行相应的更新。

类图:



根据类图我们不难看出观察者模式的结构:

Subject:主题接口,用于注册观察者或移除观察者。

Observer:观察者接口,所有具体的观察者都必须实现这个接口,一个主题可以有多个观察者。该接口只有一个update方法,当主题状态改变时,该方法被调用。

ConcreteSubject:具体主题,实现Subject接口,并且实现了notifyObserver方法,用于改变状态时通知Observer。

ConcreteObsever:具体观察者,实现Observer接口,具体观察者必须注册具体主题,便于接收更新,具体观察者可以是多个。

在学习观察者模式时,《Head First设计模式》一书中引入了一个栗子:

当天气发生变化时(温度,湿度,气压),通知各个气象站,修改气象板相应的数据。

观察者接口:

public interface Observer {
public void update(float temp, float humidity, float pressure);
}


主题接口:

public interface Subject {
//添加观察者
public void register(Observer observer);
//移除观察者
public void remove(Observer observer);
//当主题发生变化时,通知观察者
public void notifyObserver();
}


天气数据(具体主题):

public class WeatherData implements Subject {
//观察者可能是多个,所以应该是一个集合
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;

public WeatherData() {
observers = new ArrayList<>();
}

@Override
public void register(Observer observer) {
observers.add(observer);
}

@Override
public void remove(Observer observer) {
int i = observers.indexOf(observer);
if(i >= 0)
observers.remove(i);
}

@Override
public void notifyObserver() {
for (int i = 0; i < observers.size() ; i++) {
Observer observer = observers.get(i);
observer.update(temperature, humidity, pressure);
}
}

public void measurementsChanged(){
notifyObserver();
}

public void setMeasurements(float temperature, float humidity, float pressure){
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}


气象站1:

public class WeatherStationOne implements Observer {
private float temperature;
private float humidity;
private Subject weatherDate;

public WeatherStationOne(Subject weatherDate) {
this.weatherDate = weatherDate;
weatherDate.register(this);
}

@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}

public void display(){
System.out.println("WeatherStationOne temperature=" + temperature + ";humidity" + humidity);
}
}

气象站2:
public class WeatherStationTwo implements Observer{
private float temperature;
private float pressure;
private Subject weatherDate;

public WeatherStationTwo(Subject weatherDate) {
this.weatherDate = weatherDate;
weatherDate.register(this);
}

@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.pressure = pressure;
display();
}

public void display(){
System.out.println("WeatherStationTwo temperature=" + temperature + ";pressure" + pressure);
}

}

测试类:
public class Client {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
WeatherStationOne weatherStationOne= new WeatherStationOne(weatherData);
WeatherStationTwo weatherStationTwo = new WeatherStationTwo(weatherData);
weatherData.setMeasurements(33.5f,34.2f,35.7f);
weatherData.setMeasurements(33.12f, 66.66f, 99.99f);
weatherData.setMeasurements(44.44f, 55.55f, 66.696f);
}
}

测试结果:



以上即做到了,当数据发生变化时,通知到具体的各个气象站。

以上的观察者是我们自己来实现的,事实上,在JDK中已经内置了对观察者模式的支持。

修改WeatherData类为WeatherDataForJDK:此处需要继承jdk内置的Obserable类public class WeatherDataForJDK extends Observable{
private float temperature;
private float humidity;
private float pressure;

public WeatherDataForJDK() {
}
public void measurementsChanged(){
setChanged();
notifyObservers();
}

public void setMeasurements(float temperature, float humidity, float pressure){
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}

public float getTemperature() {
return temperature;
}

public void setTemperature(float temperature) {
this.temperature = temperature;
}

public float getHumidity() {
return humidity;
}

public void setHumidity(float humidity) {
this.humidity = humidity;
}

public float getPressure() {
return pressure;
}

public void setPressure(float pressure) {
this.pressure = pressure;
}
}
修改WeatherStationOne类为WeatherStationOneForJDK: 此处需要实现JDK内置的Observer接口

public class WeatherStationOneForJDK implements Observer{
private Observable observable;
private float temperature;
private float humidity;

public WeatherStationOneForJDK(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}

@Override
public void update(Observable o, Object arg) {
if(o instanceof WeatherDataForJDK){
WeatherDataForJDK weatherDataForJDK = (WeatherDataForJDK) o;
this.temperature = weatherDataForJDK.getTemperature();
this.humidity = weatherDataForJDK.getHumidity();
display();
}
}

public void display(){
System.out.println("WeatherStationOne temperature=" + temperature + ";humidity" + humidity);
}
}

同理,修改WeatherStationTwo为WeatherStationTwoForJDK:
public class WeatherDataTwoForJDK implements Observer {
private Observable observable;
private float temperature;
private float pressure;

public WeatherDataTwoForJDK(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}

@Override
public void update(Observable o, Object arg) {
if (o instanceof WeatherDataForJDK){
WeatherDataForJDK weatherDataForJDK = (WeatherDataForJDK) o;
this.temperature = weatherDataForJDK.getTemperature();
this.pressure = weatherDataForJDK.getPressure();
display();
}
}

public void display(){
System.out.println("WeatherStationTwo temperature=" + temperature + ";pressure" + pressure);
}
}


测试类:
public class Client {
public static void main(String[] args) {
WeatherDataForJDK weatherDataForJDK = new WeatherDataForJDK();
WeatherStationOneForJDK weatherStationOne= new WeatherStationOneForJDK(weatherDataForJDK);
WeatherDataTwoForJDK weatherStationTwo = new WeatherDataTwoForJDK(weatherDataForJDK);
weatherDataForJDK.setMeasurements(33.5f,34.2f,35.7f);
weatherDataForJDK.setMeasurements(33.12f, 66.66f, 99.99f);
weatherDataForJDK.setMeasurements(44.44f, 55.55f, 66.696f);
}
}

测试结果:



各位一定要亲自动手敲一遍哦。着实很神奇呢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息