设计原则
- 面向接口编程
- 对象之间交互必须松耦合,借助抽象接口来实现交互动作的解耦
定义和实现思路
- 为了实现交互对象之间的松耦合,把交互行为抽象为两个接口。一个主题接口(Subject)、一个观察者接口(Observer)。两者使用彼此的接口进行交互,不依赖具体实现。所谓松耦合就是如此
- Subject唯一依赖的就是一个实现了Observer接口的对象列表
- 当Subject状态发生改变时,调用Observer接口发出通知,与其进行交互
UML模型
其中包含Subject(可观察者接口)、Observer(观察者接口)、额外的行为接口(DisplayElement);它们的具体实现类:WeatherData(可观察者具体实现,状态更改时通知观察者)、CurrentConditionsDisplay、StatisticsDisplay...(观察者,接收WeatherData的状态变更通知、与其进行交互)
具体实现代码
/**
* 可观察者接口
* @author luhuancheng
* @since 2018/3/26 22:44
*/
public interface Subject {
/**
* 注册观察者
*
* @param observer
*/
void registerObserver(Observer observer);
/**
* 移除观察者
*
* @param observer
*/
void removeObserver(Observer observer);
/**
* 通知观察者
*/
void notifyObserver();
}
/**
* 主题接口实现类
*
* @author luhuancheng
* @since 2018/3/26 22:52
*/
public class WeatherData implements Subject {
private List<Observer> observerList;
private Float temperature;
private Float humidity;
private Float pressure;
public WeatherData() {
this.observerList = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
observerList.add(observer);
}
@Override
public void removeObserver(Observer observer) {
int i = observerList.indexOf(observer);
if (i >= 0) {
observerList.remove(i);
}
}
@Override
public void notifyObserver() {
for (Observer observer : observerList) {
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();
}
}
/**
* 观察者接口
*
* @author luhuancheng
* @since 2018/3/26 22:44
*/
public interface Observer {
void update(Float temp, Float humidity, Float pressure);
}
/**
* 观察者的另一个行为接口
*
* @author luhuancheng
* @since 2018/3/26 22:46
*/
public interface DisplayElement {
void display();
}
/**
* @author luhuancheng
* @since 2018/3/26 22:59
*/
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private Float temperature;
private Float humidity;
private Subject subject;
public CurrentConditionsDisplay(Subject subject) {
this.subject = subject;
// 注册观察者
subject.registerObserver(this);
}
@Override
public void display() {
System.out.println(String.format("Current conditions: %s F degrees and %s humidity", temperature, humidity) );
}
@Override
public void update(Float temp, Float humidity, Float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
}
/**
* 客户端调用代码
*
* @author luhuancheng
* @since 2018/3/26 23:02
*/
public class Client {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay display = new CurrentConditionsDisplay(weatherData);
// 此处可以添加不同的实现了Observer接口的类,在之后主题状态发生变化时,会得到通知
weatherData.setMeasurements(80F, 65F, 30.4F);
}
}
调用时序图
总结
- 可观察者和观察者之间利用接口实现了松耦合方式交互
- 可观察者和观察者之间定义了一对多关系
- 与多个观察者交互时,不可依赖其特定的通知次序