设计模式之观察者模式
观察者模式感觉是23种设计模式之中最简单的一种,当你需要获取一个变化的对象的部分信息时,可以考虑使用这种设计模式,它可以在你关注的对象改变时,及时的通知到你,并将你关心的值也传给你.观察者模式适用于类似订阅/发布的地方.
被观察主体实现自Subject接口
package com.yczuoxin.pattern.subject;
import com.yczuoxin.pattern.observer.Observer;
public interface Subject {
void registerObserver(@NotNull Observer observer);
void removeObserver(@NotNull Observer observer);
void notifyObserver();
}
观察者主题实现自Observer接口
package com.yczuoxin.pattern.observer;
public interface Observer {
void update(float temperature, float humidity, float pressure);
}
例如常见的气象公布板WeatherData实体类实现
package com.yczuoxin.pattern.subject;
import com.sun.istack.internal.NotNull;
import com.yczuoxin.pattern.observer.Observer;
import java.util.ArrayList;
public class WeatherData implements Subject {
private ArrayList<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<>();
}
@Override
public void registerObserver(@NotNull Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(@NotNull Observer observer) {
int index = observers.indexOf(observer);
if(index >= 0){
observers.remove(observer);
}
}
@Override
public void notifyObserver() {
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
public void setMeasurements(float temperature, float humidity, float pressure){
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurements();
}
public void measurements(){
notifyObserver();
}
}
编写观察者对象输出语句的接口ElementDisplay
package com.yczuoxin.pattern.observer;
public interface ElementDisplay {
void display();
}
编写第一个观察者对象CurrentConditionDisplay实体类,该类实现Obsever接口以及ElementDisplay接口,该实体类观察气象公布板上所有的信息
package com.yczuoxin.pattern.observer;
import com.yczuoxin.pattern.subject.Subject;
public class CurrentConditionsDisplay implements Observer, ElementDisplay {
private Subject weatherData;
private float temperature;
private float humidity;
private float pressure;
public CurrentConditionsDisplay(Subject weatherData){
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("当前温度为:" + temperature + "℃"+ "\n" +
"当前湿度为:" + humidity + "%" + "\n" +
"当前大气压为:" + pressure + "Pa");
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
display();
}
}
编写第二个观察者对象GeneralDisplay实体类,该类实现Obsever接口以及ElementDisplay接口,该实体类观察气象公布板上部分的信息
package com.yczuoxin.pattern.observer;
import com.yczuoxin.pattern.subject.Subject;
public class GeneralDisplay implements Observer,ElementDisplay {
private Subject weatherData;
private float temperature;
private float humidity;
public GeneralDisplay(Subject weatherData){
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("当前温度为:" + temperature + " ℃"+ "\n" +
"当前湿度为:" + humidity + " %" + "\n");
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
}
使用测试类去测试我们写的代码
package com.yczuoxin.pattern;
import com.yczuoxin.pattern.observer.CurrentConditionsDisplay;
import com.yczuoxin.pattern.observer.GeneralDisplay;
import com.yczuoxin.pattern.subject.Subject;
import com.yczuoxin.pattern.subject.WeatherData;
public class ObserverTest {
public static void main(String[] args) {
Subject weatherData = new WeatherData();
CurrentConditionsDisplay currentConditionsDisplay =
new CurrentConditionsDisplay(weatherData);
GeneralDisplay generalDisplay = new GeneralDisplay(weatherData);
((WeatherData) weatherData).setMeasurements(32.5f,45.2f,103.2f);
}
}
当前温度为:32.5 ℃
当前湿度为:45.2 %
当前大气压为:103.2 Pa
当前温度为:32.5 ℃
当前湿度为:45.2 %
结果可以看到当公布板的值改变后,两个观察者对象实体立即获取了公布板上公布的所需要的值.这就是观察者模式要达到的效果.观察者模式的主体接口需要有三个主方法:
1.注册观察者的registerObserver();
2.通知观察者主体信息已被修改的notifyObserver(),该方法如果传入参数就是主动推送的的方式,也可以提供getter,setter方法让观察者自己去拉取数据.
3.移除观察者的removeObserver();
而观察者需要维护主体,并有一个主方法update();
JDK对于观察者模式也提供有自己的方法,被观察者要继承自Observable抽象类,而观察者则需要继承自Observer抽象类.Observable抽象类中维护了一个私有boolean变量changed,只有当changed为true时才触发通知观察者,这样做使得通知观察者的时机更加灵活,是值得借鉴的一个点,但是由于JDK提供的这两个皆为抽象类,只得去继承,根据java的单继承的原则,会对扩展该方法产生限制,所以使用的时候要斟酌清楚其中的利弊.