简介
首先,我们来看一个需求。当某一件事情发生的时候会去通知另外一件事情的执行。例如,小孩子哭肯定会引起爸爸妈妈的注意,接收到消息会引起QQ或者微信的闪动…等等。总之呢,对于一个你想要监听的方法,你可以使用观察者模式进行设计。
观察者模式在23种设计模式中也是比较常用的,他能做得到的很多;包括事件监听、发布订阅、消息通知,甚至可以帮我们一理解面向切面AOP。
传统方式
我们先来看传统的方法,直接暴力解决,当被观察的方法触发时,就会调用对应的观察方法。
代码如下:
被监听者:
public class Event {
public void touch(){
// 自己的业务逻辑
System.out.println("事件触发啦");
// 调用监听者的方法,告知监听者被监听者已经执行了
new One().listenOne();
new Two().listenTwo();
}
}
监听者A:
public class One {
public void listenOne(){
System.out.println("监听者一号");
}
}
监听者B:
public class Two {
public void listenTwo(){
System.out.println("监听者二号");
}
}
我们看到代码非常的简单,就短短的几行,但是却很不利于扩展。
当我们还要其他监听者要监听的话就需要在被监听的方法中继续添加监听者,并且每个监听者要执行的方法不同,对于不同的监听者都有不同的处理机制,所以传统方法根本不利于系统的扩展。
此时,就要引入我们的观察者模式。
引入观察者
观察者模式也是灵活运用了多态以及面向抽象编程这一设计原则,将公共的业务观察者抽取出来,统一由接口调用相同的方法,方法的内部逻辑交由子类自行处理。
代码如下:
公共抽象监听者:
public interface IListener {
// 规定统一的方法
public void handler();
}
具体监听者A:
public class ListenOne implements IListener {
@Override
public void handler() {
kill();
}
public void kill(){
System.out.println("抽你");
}
}
具体监听者B:
public class ListenTwo implements IListener{
@Override
public void handler() {
homehome();
}
public void homehome(){
System.out.println("哄哄");
}
}
被观察者:
public class TouchE {
// 观察者队列
private List<IListener> listeners = new ArrayList<>();
public TouchE(){
// 此处添加观察者也可以让客户端自行添加,根据业务需求改
listeners.add(new ListenOne());
listeners.add(new ListenTwo());
}
public void cry(){
System.out.println("我哭了");
// 调用观察者处理
for (IListener listen:listeners) {
listen.handler();
}
}
}
我们可以看到,使用观察者模式确实带来了很多好处。
- 新增观察者只需要将其加入队列即可
- 被观察者触发时,都是面向接口调用公共处理方法,不同的观察者(即子类)在自行添加自己的逻辑
JDK的支持
如果使用Java语言进行开发,JDK已经为我们提供好了相应的接口和抽象类。
- 观察者只需要实现
Observer接口并重写update()方法,当被观察者要通知观察者就会执行update方法中的逻辑 - 被观察者则继承
Observable类,在需要触发观察者的方法加入setChanged()和notifyObservers()这两个方法进行通知
代码如下:
观察者:
public class Listener implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("o==="+o);
System.out.println("arg==="+arg);
System.out.println("监听");
}
}
被观察者:
// 触发事件
public class TouchEvent extends Observable {
public void happen(){
System.out.println("发生方法");
setChanged();
notifyObservers("TouchEvent123123");
}
}
Main方法:
public class Main {
public static void main(String[] args) {
// 创建被观察者
TouchEvent touchEvent = new TouchEvent();
// 创建监听者
Listener listener = new Listener();
// 添加观察者
touchEvent.addObserver(listener);
touchEvent.happen();
}
}
JDK提供的方式是让我们手动加入观察者,代码总体来说也还是比较简单。
我们来简单解读一下参数含义。
被观察者
- setChanged()方法用于改变状态,不改变状态无法触发到观察者
- notifyObservers()方法用于向观察者传递参数,他是一个重载方法,可以传一个参数或者不传
观察者
- Observable o :被观者类的全限定类名
- Object arg :被观察者通过
notifyObservers()方法传递过来的参数,没有就是空,不然传什么就是什么
UML类图
JDK类图,直接封装好了,这两个类对外显示都没什么关系:

自实现观察者:

其实JDK提供的和子实现的是一样的,只不过套了一个壳,封装好了方法,简单看一下源码:


小结
从观察者模式中又看到,面向抽象编程的灵活性。可以很好的帮助我们对系统进行扩展;并且观察者模式在许多地方都有用多,包括许多的监听器,监听事件,Spring中的ApplicationListener也涉及到了观察者模式。也算是23种比较常用的一种。
本文介绍观察者模式的基本概念及其在Java中的实现方式。通过对比传统方法与观察者模式,展示了如何利用多态和面向抽象编程的原则来提高系统的扩展性和灵活性。同时介绍了JDK对观察者模式的支持。
&spm=1001.2101.3001.5002&articleId=109622876&d=1&t=3&u=46c73a47ab784d6b9e0a784100e07922)
346

被折叠的 条评论
为什么被折叠?



