~
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
别名:发布-订阅模式
将一个系统分割成一系列相互协作的类有一个常见的副作用:需要维护相关对象间的致性,我们不希望为了维持一致性而使各类紧密耦合,因为这样降低了它们的可重用性。
说人话就是:
【产品】:开发小哥,我需要你设计一个天气预报显示大屏,气象站会给你发送数据,你需要把它展示到大屏里,OK吗?
【开发】:OJBK!秒秒钟搞定一切!代码立马出来!
void getTemperature () {
// 从气象站获取发送过来的温度数据
// getData();
// ................................
// 显示到大屏里面去
// showDataToScreen();
// ................................
}
void getMisture () {
// 从气象站获取发送过来的湿度数据
// getData();
// ................................
// 显示到大屏里面去
// showDataToScreen();
// ................................
}
void getAirindex () {
// 从气象站获取发送过来的空气指数数据
// getData();
// ................................
// 显示到大屏里面去
// showDataToScreen();
// ................................
}
【BOSS】:磕大头!宁是准备每获取一次数据就把代码CV一遍吗?你不累吗?
【开发】:老大,我一点都不累!就是复制粘贴一下呀!
【BOSS】:如果我现在不需要同步更新天气指数呢?删代码吗?
【开发】:对啊!一秒钟就能删掉!( •̀ ω •́ )✧
【BOSS】:重写?
于是乎,我们开启了关于设计模式的经典书籍阅读之旅
/**
* 观察主题接口
*/
public interface Observable{
public void addObserver(Observer observer); // 添加观察者
public void removeObserver(Observer observer); // 移除观察者
public void notifyObservers(WeatherData data); // 通知所有观察者
}
/**
* 观察者
*/
public interface Observer {
public abstract void update(WeatherData data);
}
/**
* 天气主题
*
*/
public class Weather implements Observable {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(WeatherData data) {
for (Observer observer : observers)
observer.update(data);
}
}
观察者模式的设计思路:
简单来说,
❝如果看着有点模棱两可,就看完本文后,访问专题设计模式开源项目,里面有具体的代码示例,链接在最下面 ❞
JDK中已经对观察者模式有具体的实现,代码非常简单,如下所示:
具体目标:
public class ObservableApp extends Observable {
private long curr;
public ObservableApp(long curr) {
this.curr = curr;
}
public void change(long newStr) {
this.curr = newStr;
// 更改状态,发送通知
setChanged();
notifyObservers(newStr);
}
@Override
protected synchronized void setChanged() {
super.setChanged();
}
}
具体观察者:
public class ObserverA implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println(MessageFormat.format("ObserverA -> {0} changed, Begin to Work. agr is:{1}", o.getClass().getSimpleName(), arg));
}
}
Main方法:
public class App {
public static void main(String[] args) throws InterruptedException {
ObservableApp app = new ObservableApp(System.currentTimeMillis());
System.out.println(app.getCurr());
app.addObserver(new ObserverA());
app.addObserver(new ObserverB());
Thread.sleep(1000);
long curr = System.currentTimeMillis();
app.change(curr);
System.out.println(app.getCurr());
}
}
// 输出如下:
// 1589688733464
// ObserverB -> ObservableApp changed, Begin to Work. agr is:1,589,688,734,469
// ObserverA -> ObservableApp changed, Begin to Work. agr is:1,589,688,734,469
// 1589688734469
通知发给观察者,通知携带参数,这就是推,对应JDK方法中的:notifyObservers(Object arg)
通知发给观察者,通知不携带参数,需要观察者自己去主动调用get方法获取数据,这就是拉
对应JDK方法中的:notifyObservers(),仅告知观察者数据发生了变化,至于数据的详情需要观察者主动到主题中pull数据
拉模型强调的是目标不知道它的观察者,而推模型假定目标知道一些观察者的需要的信息。推模型可能使得观察者相对难以复用,因为目标对观察者的假定可能并不总是正确的。另一方面。拉模型可能效率较差,因为观察者对象需在没有目标对象帮助的情况下确定什么改变了。
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern),比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式
「附上GOF一书中对于观察者模式的UML图:」
观察者模式UML图
GitHub地址:https://github.com/kkzhilu/Kerwin-DesignPattern