1.简介
–《百度百科 观察者模式》
观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在观察者模式中,主体是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅并接收通知。观察者模式不仅被广泛应用于软件界面元素之间的交互,在业务对象之间的交互、权限管理等方面也有广泛的应用。 [1]
观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。
观察者设计模式定义了对象间的一种一对多的组合关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。
–《Head First设计模式(中文版)》
观察者模式 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
2.具体操作及实现
举例:新闻报道,由记者获取最新新闻,相关新闻媒体发布新闻
整体结构如下所示:
主题类(被观察者)Subject 接口:
package cn.shentianlan.studytest.designmode.observer.example;
/**
* @author 渊蓝
* @version 1.0
* @description 主题(被观察者)
* @date 2021/10/12 22:20
*/
public interface Subject {
/**
* 注册观察者
* @param observer
*/
void registerObserver(Observer observer);
/**
* 移除观察者
* @param observer
*/
void removeObserver(Observer observer);
/**
* 通知观察者
*/
void notifyObserver();
}
观察者 Observer:
package cn.shentianlan.studytest.designmode.observer.example;
/**
* @author 渊蓝
* @version 1.0
* @description 观察者
* @date 2021/10/12 22:21
*/
public interface Observer {
void update(String news);
}
主体数据 被观察者对象 记者 Reporter
package cn.shentianlan.studytest.designmode.observer.example;
import java.util.ArrayList;
import java.util.List;
/**
* @author 渊蓝
* @version 1.0
* @description 记者
* @date 2021/10/12 22:23
*/
public class Reporter implements Subject {
//观察者队列
private List<Observer> observerList;
public Reporter() {
this.observerList = new ArrayList<>();
}
private String news;
@Override
public void registerObserver(Observer observer) {
if (!observerList.contains(observer)){
observerList.add(observer);
}
}
@Override
public void removeObserver(Observer observer) {
if (!observerList.isEmpty() ){
observerList.remove(observer);
}
}
@Override
public void notifyObserver() {
if (!observerList.isEmpty()){
observerList.forEach(observer -> {
observer.update(news);
});
}
}
public String getNews() {
return news;
}
public void setNews(String news) {
this.news = news;
notifyObserver();
}
}
观察者对象 PeoplesNetwork XinHuaNet
package cn.shentianlan.studytest.designmode.observer.example;
/**
* @author 渊蓝
* @version 1.0
* @description 人民网
* @date 2021/10/12 22:31
*/
public class PeoplesNetwork implements Observer{
public PeoplesNetwork(Subject subject) {
subject.registerObserver(this);
}
@Override
public void update(String news) {
System.out.println("人民网:"+news);
}
}
package cn.shentianlan.studytest.designmode.observer.example;
/**
* @author 渊蓝
* @version 1.0
* @description 新华网
* @date 2021/10/12 22:34
*/
public class XinHuaNet implements Observer {
public XinHuaNet(Subject subject) {
subject.registerObserver(this);
}
@Override
public void update(String news) {
System.out.println("新华网:"+news);
}
}
测试 ObserverTest:
package cn.shentianlan.studytest.designmode.observer.example;
/**
* @author 渊蓝
* @version 1.0
* @description 观察者模式测试类
* @date 2021/10/12 22:37
*/
public class ObserverTest {
public static void main(String[] args) {
Reporter reporter = new Reporter();
PeoplesNetwork peoplesNetwork = new PeoplesNetwork(reporter);
XinHuaNet xinHuaNet = new XinHuaNet(reporter);
reporter.setNews("记者小蓝报道:母猪正在试图爬树");
//移除人民网观察者
reporter.removeObserver(peoplesNetwork);
reporter.setNews("记者小李报道:最近有台风登陆,请市民出行注意安全");
}
}
结果:
人民网:记者小蓝报道:母猪正在试图爬树
新华网:记者小蓝报道:母猪正在试图爬树
新华网:记者小李报道:最近有台风登陆,请市民出行注意安全
3 Java内置的观察者对象解析
使用Java内置的Observable(被观察者)和Observer(观察者)对上面的案例进行修改(注意引用的包是java.util中的)
主体数据 被观察者对象 记者 Reporter
package cn.shentianlan.studytest.designmode.observer.javaExample;
import java.util.Observable;
/**
* @author 渊蓝
* @version 1.0
* @description 记者
* @date 2021/10/12 23:00
*/
public class Reporter extends Observable {
private String news;
public void setNews(String news) {
this.news = news;
//setChanged()方法用来标记状态已经改变的事实,好让notifyObservers()知道当它被调用时应该更新观察者。
setChanged();
notifyObservers(news);
}
}
观察者对象 PeoplesNetwork XinHuaNet
package cn.shentianlan.studytest.designmode.observer.javaExample;
import java.util.Observable;
import java.util.Observer;
/**
* @author 渊蓝
* @version 1.0
* @description 人民网
* @date 2021/10/12 23:01
*/
public class PeoplesNetwork implements Observer {
public PeoplesNetwork(Observable observable) {
observable.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
System.out.println("人民网:"+arg);
}
}
package cn.shentianlan.studytest.designmode.observer.javaExample;
import java.util.Observable;
import java.util.Observer;
/**
* @author 渊蓝
* @version 1.0
* @description 新华网
* @date 2021/10/12 22:34
*/
public class XinHuaNet implements Observer {
public XinHuaNet(Observable observable) {
observable.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
System.out.println("新华网:"+arg);
}
}
测试 ObserverTest:
package cn.shentianlan.studytest.designmode.observer.javaExample;
/**
* @author 渊蓝
* @version 1.0
* @description 使用Java内置观察者模式测试类
* @date 2021/10/12 23:20
*/
public class ObserverTest {
public static void main(String[] args) {
Reporter reporter = new Reporter();
PeoplesNetwork peoplesNetwork = new PeoplesNetwork(reporter);
XinHuaNet xinHuaNet = new XinHuaNet(reporter);
reporter.setNews("记者小蓝报道:最近天气不错");
//移除人民网观察者
reporter.deleteObserver(peoplesNetwork);
reporter.setNews("记者小李报道:最近可能会下暴雨");
}
}
结果:
新华网:记者小蓝报道:最近天气不错
人民网:记者小蓝报道:最近天气不错
新华网:记者小李报道:最近可能会下暴雨
4 Java内置的观察者对象存在的缺陷(Head First设计模式(中文版))
- java.util.Observable 是一个类 而不是一个接口 ,这限制了它的使用和复用。这不符合设计原则(针对接口编程,而非针对实现编程)。
- 由此会造成的问题:
- 首先,因为Observable是一个“类”,导致我们必须设计一个类继承它。如果某类想同时具有Observable类和另一个超类的行为,就会陷入两难,毕竟Java不支持多重继承。这限制了Observable的复用潜力(而增加复用潜力不正是我们使用模式最原始的动机吗?)。
- 再者,因为没有Observable接口,所以你无法建立自己的实现,和Java内置的Observer API搭配使用,也无法将java.util的实现换成另一套做法的实现(比方说,如果你能够扩展java.util.Observable,那么Observable“可能”可以符合你的需求。否则,你可能需要自己实现这一整套观察者模式。如果你看看Observable API,你会发现setChanged()方法被保护起来了(被定义成protected)。这意味着:除非你继承自Observable,否则你无法创建Observable实例并组合到你自己的对象中来。这个设计违反了第二个设计原则:“多用组合,少用继承”
5 JDK中使用观察者模式的案例
JavaBeans和Swing中,也都实现了观察者模式
让我们看看一个简单的SwingAAPI:JButton。如果你观察一下JButton的超类AbstractButton,会看到许多增加与删除倾听者(listener)的方法,这些方法可以让观察者感应到Swing组件的不同类型事件。比方说:ActionListener让你“倾听”可能发生在按钮上的动作,例如按下按钮。你可以在Swing API中找到许多不同类型的倾听者。