springboot笔记④——观察者设计模式(含jdk和spring实现的)

观察者设计模式

观察者设计模式中存在三种对象,分别是事件源、事件和监听器。其中事件源相当于被观察者,被观察者会触发事件,而监听器会在触发的事件中通知观察者。

特点

  • 持有监听的观察者的引用
  • 支持增加和删除观察者
  • 主题状态改变,通知观察者

自己实现的观察者模式

监听器对象(观察者)

只需要提供一个接口

public interface GameListener {
	public void update(GameEvent gameEvent);
}

想要监听的对象只需要实现此接口就可以成为监听器,例如下面这个Person对象就是一个观察者。

public class Person implements GameListener{
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Person(String name) {
		this.name = name;
	}

	public void update(GameEvent gameEvent){
		if(gameEvent.getType() == 1){
			System.out.println(name+"开始休息");
		}
	}
}

事件

事件对象,在被观察者中会触发的事件

public class GameEvent {
	private String context;

	private int type;

	public String getContext() {
		return context;
	}

	public void setContext(String context) {
		this.context = context;
	}

	public int getType() {
		return type;
	}

	public void setType(int type) {
		this.type = type;
	}
}

被观察者

这里就是核心,关键就是被观察者保留观察者的引用,这样触发事件的时候就可以通知观察者,这样就可以解放观察者的观察所带来的资源浪费。

public class PlayGame implements Runnable{

	// 监听器
	private List<GameListener> gameListeners;

	public void addPlayer(GameListener gameListener){
		gameListeners.add(gameListener);
	}

	public PlayGame() {
		this.gameListeners = new ArrayList<>();
	}

	@Override
	public void run() {
		System.out.println("开始打游戏");
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("需要休息一下");
		// 触发事件
		GameEvent gameEvent = new GameEvent();
		gameEvent.setType(1);
		// 循环遍历调用观察者方法
		for (GameListener gameListener : gameListeners) {
			gameListener.update(gameEvent);
		}

	}
}

测试

public static void main(String[] args) {
	// 创建监听者
	Person zdd = new Person("zdd");
	Person pipi = new Person("pipi");
	// 创建被观察者
	PlayGame playGame = new PlayGame();
	// 添加监听器
	playGame.addPlayer(zdd);
	playGame.addPlayer(pipi);
	Thread thread = new Thread(playGame);
	thread.run();
}

JDK实现的观察者模式

JDK的观察者模式的实现依赖于下面两个类和接口

  • Observable:类,被观察者需要继承此类
  • Observer:接口,观察者需要实现此接口,在update方法中实现事件触发的方法

而且JDK实现的观察者只需要我们手动创建两个对象,一个是被观察者,一个是观察者。

被观察者

注意如果需要触发事件调用setChangednotifyObservers方法,而且任何一个方法没有调用都会触发事件失败。

public class PlayGame extends Observable implements Runnable{

	@Override
	public void run() {
		System.out.println("开始打游戏");
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("需要休息一下");
		// 触发事件
		// 改变状态
		setChanged();
		// 唤醒观察者
		// 可以传递参数,在观察者中的update方法中可以拿到
		notifyObservers();

	}
}

观察者

事件触发会调用update方法

public class Person implements Observer {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Person(String name) {
		this.name = name;
	}


	/**
	 * 第一个参数是事件源,也就是被观察者
	 * 第二个参数是notifyObservers方法传递进来的参数
	 * @param o
	 * @param arg
	 */
	@Override
	public void update(Observable o, Object arg) {
		System.out.println(name+"开始休息");
		System.out.println(o);
		System.out.println(arg);
	}
}

测试

public static void main(String[] args) {
	// 创建监听者
	Person zdd = new Person("zdd");
	Person pipi = new Person("pipi");
	// 创建被观察者
	PlayGame playGame = new PlayGame();
	// 添加监听器
	playGame.addObserver(zdd);
	playGame.addObserver(pipi);
//  删除单个监听器
//	playGame.deleteObserver(zdd);
//  删除所有监听器
//	playGame.deleteObservers();
	Thread thread = new Thread(playGame);
	thread.run();
}

优点

JDK的观察者模式各个组件之间的耦合度很低,而且Observable提供了很多API,可以很方便完成触发事件,更改监听器等等操作。

Spring的观察者模式

spring框架中同样存在观察者模式,而且我们得知道spring中的被观察对象自然是spring本身。而且spring中存在很多可以触发的事件,我们可以通过扩展这些的事件来间接使用它,不过在此之前我们需要先了解一下spring中的事件。

spring的事件总览

spring中最重要的事件类就是ApplicationEvent,它是spring实现的事件父类,它有两个重要子类ApplicationContextEvent和RequestHandledEvent。

而ApplicationContextEvent又有几个重要的子类:

  • ContextStartedEvent:在上下文启动时被启动
  • ContextStoppedEvent:在上下文停止时被启动
  • ContextRefreshedEvent:当上下文被刷新时产生
  • ContextClosedEvent:在上下文关闭时产生

它们的继承关系图如下
在这里插入图片描述

RequestHandledEvent

这个事件与request请求相关联,当在ApplicationContext中处理请求时,它们被引发。不过这里不会对这类事件进行分析。

ApplicationContextEvent

它与应用程序上下文相关联,它们应用于由org.springframework.context.ApplicationContext引发的事件(其构造函数传入的是ApplicationContext类型的参数)。

这样,我们就可以直接通过应用程序上下文的生命周期来得到所发生的事件:ContextStartedEvent在上下文启动时被启动,当它停止时启动ContextStoppedEvent,当上下文被刷新时产生ContextRefreshedEvent,最后在上下文关闭时产生ContextClosedEvent

监听ApplicationContextEvent的子类事件

我们可以直接监听ApplicationContextEvent中任意一个子类,这里演示的是监听ContextStartedEvent事件,只需要创建一个监听对象实现ApplicationListener<泛型>,在泛型中写上需要监听的事件。

@Component
public class MyMonitor implements ApplicationListener<ContextStartedEvent> {

	@Override
	public void onApplicationEvent(ContextStartedEvent event) {
		System.out.println("自定义监听");
	}
}

ContextStartedEvent事件需要执行上下文对象的start方法
在这里插入图片描述
在这里插入图片描述

监听自定义事件

我们同样可以直接继承ApplicationEvent创建一个自定义的事件。

不过需要注意的是我们创建的事件想要触发也必须得我们自己去主动去触发,这里我通过一个bean的方法触发的事件。

  • 自定义事件
public class MyContextEvent extends ApplicationEvent {

	/**
	 * Create a new ApplicationEvent.
	 *
	 * @param source the object on which the event initially occurred (never {@code null})
	 */
	public MyContextEvent(Object source) {
		super(source);
	}
}
  • 监听对象
@Component
public class EventMonitor implements ApplicationListener<MyContextEvent> {
	@Override
	public void onApplicationEvent(MyContextEvent event) {
		System.out.println("自定义事件监听");
	}
}
  • 触发对象
@Component
public class Trigger {

	@Autowired
	ApplicationContext applicationContext;

	public void triggerEvent(){
		System.out.println("triggerEvent");
		// 触发事件
		applicationContext.publishEvent(new MyContextEvent(applicationContext));
	}

}
  • 测试
public static void main(String[] args) {
	AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
	Trigger trigger = ac.getBean(Trigger.class);
	// 触发事件
	trigger.triggerEvent();
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值