观察者模式
观察者模式定义
首先需要说明的是,java已经帮我们创建好了被观察者和观察者接口,为了搞清楚观察者模式流程,我们先自己实现,然后再用java提供的接口来实现。
什么是观察者模式,观察者模式又叫发布订阅模式,简单点就是被观察者状态变化时,通知观察者
我们先从最简单的例子开始
创建观察者接口
public abstract class Observer {
protected abstract void update(String context);
}
创建被观察者接口
public abstract class Observable {
public Vector<Observer> obs = new Vector();
protected void addObserver(Observer obs) {
this.obs.add(obs);
}
protected void deleteObserver(Observer obs) {
this.obs.remove(obs);
}
protected void notifyObservers(String context) {
for (Observer observer : obs) {
observer.update(context);
}
}
}
创建观察者接口实现类
public class ConcreteObserver extends Observer {
@Override
protected void update(String context) {
System.out.println("Observer receive msg: " + context);
}
}
创建被观察者接口实现类
public class ConCreteObservable extends Observable {
public void doSomething() {
System.out.println("Observable: I am watching movie");
super.notifyObservers("observable is watching movie");
}
}
客户端
public class Client {
public static void main(String[] args) {
// 定义一个被观察者
ConCreteObservable conCreteObservable = new ConCreteObservable();
// 添加观察者
conCreteObservable.addObserver(new ConcreteObserver());
conCreteObservable.doSomething();
}
}
输出结果
Observable: I am watching movie
Observer receive msg: observable is watching movie
Observable 和 Observer
明白原理之后,我们用java自带的接口Observable ,Observer 来实现一个场景:气象局发布天气预警,电视台收到消息发布出去
public interface IWeather {
//气象部门发布下雨公告
void rain();
}
public class Weather extends Observable implements IWeather {
@Override
public void rain() {
System.out.println("气象台发布下雨预警");
super.setChanged();
super.notifyObservers("今夜到明天上午局部地区有暴雨,请及时防范");
}
}
public class CCTV implements Observer {
@Override
public void update(Observable o, Object arg) {
//在实际中一般的做法是:观察者中的update方法接受两个参数,一个是被观察者,一个 是DTO(Data Transfer Object,据传输对象)
System.out.println("cctv发布气象预告:"+ arg);
}
}
public class Client {
public static void main(String[] args) {
Weather weather = new Weather();
weather.addObserver(new CCTV());
weather.rain();
}
}
输出结果:
气象台发布下雨预警
cctv发布气象预告:今夜到明天上午局部地区有暴雨,请及时防范
java中事件监听
java中还有另外一种方式可以实现观察者模式,java中定义了EventObject和EventListener接口,EventObject 相当于被观察者,EventListener 相当于观察者,下面的例子是实现对门状态变化的监听。
首先创建一个事件,继承EventObject
public class DoorEvent extends EventObject {
private Integer doorStatus;//0关闭 1打开
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
public DoorEvent(Object source) {
super(source);
}
public DoorEvent(Object source, Integer doorStatus) {
super(source);
this.doorStatus = doorStatus;
}
public Integer getDoorStatus() {
return doorStatus;
}
public void setDoorStatus(Integer doorStatus) {
this.doorStatus = doorStatus;
}
}
接着创建监听器,监听该事件
public interface DoorListener extends EventListener {
void doorEvent(DoorEvent doorEvent);
}
public class OpenDoorListener implements DoorListener {
@Override
public void doorEvent(DoorEvent doorEvent) {
Integer doorStatus = doorEvent.getDoorStatus();
if (1 == doorStatus) {
System.out.println("door is opened");
}
}
}
public class CloseDoorListener implements DoorListener {
@Override
public void doorEvent(DoorEvent doorEvent) {
Integer doorStatus = doorEvent.getDoorStatus();
if (0 == doorStatus) {
System.out.println("door is closed");
}
}
}
客户端
public class Client {
public static void main(String[] args) {
//创建监听事件
DoorEvent event = new DoorEvent("open", 1);
//开始监听
List<DoorListener> listenerList = new ArrayList<DoorListener>();
listenerList.add(new OpenDoorListener());
listenerList.add(new CloseDoorListener());
for (DoorListener doorListener : listenerList) {
doorListener.doorEvent(event)
}
}
}
spring中的事件监听
我们来看看如何在spring中使用事件监听
下面我们来实现一个智能场景:主人下班回家,打开门之后,自动打开灯光,打开空调,打开电视,其实就是捷径。
同样的,先创建一个事件
public class OpenDoorEvent extends ApplicationEvent {
public OpenDoorEvent(Object source) {
super(source);
}
}
依然创建三个监听类
打开灯光
@Component
public class OpenLightListener implements ApplicationListener<OpenDoorEvent> {
@Override
public void onApplicationEvent(OpenDoorEvent openDoorEvent) {
String source = (String) openDoorEvent.getSource();
// System.out.println(source);
System.out.println("打开灯光...");
}
}
打开电视
@Component
public class OpenTVListener implements ApplicationListener<OpenDoorEvent> {
@Override
public void onApplicationEvent(OpenDoorEvent openDoorEvent) {
String source = (String) openDoorEvent.getSource();
// System.out.println(source);
System.out.println("打开电视...");
}
}
打开空调
@Component
public class OpenKTListener implements ApplicationListener<OpenDoorEvent> {
@Override
public void onApplicationEvent(OpenDoorEvent openDoorEvent) {
String source = (String) openDoorEvent.getSource();
// System.out.println(source);
System.out.println("打开空调...");
}
}
创建service方法,使用ApplicationEventPublisher来发布事件
@Service
public class OpenDoorPublisherService {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
public void openDoor() {
OpenDoorEvent event = new OpenDoorEvent("dto json ....");
System.out.println("欢迎主人回家...");
applicationEventPublisher.publishEvent(event);
}
}
测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class Client {
@Autowired
private OpenDoorPublisherService openDoorPublisherService;
@Test
public void test() {
openDoorPublisherService.openDoor();
}
}
欢迎主人回家...
打开空调...
打开灯光...
打开电视...
如果我们像对打开顺序做排序,该怎么做呢
排序实现
SmartApplicationListener接口可以实现排序功能,因为它继承了Ordered接口,监听类做如下修改
@Component
public class OpenLightListener implements SmartApplicationListener {
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
return aClass == OpenDoorEvent.class;
}
@Override
public boolean supportsSourceType(Class<?> aClass) {
// 例如 aClass == User.class;
return true;
}
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
System.out.println("打开灯光...");
}
@Override
public int getOrder() {
//数字越小优先级越高
return 0;
}
}
必须supportsEventType和supportsSourceType都返回true,才会执行onApplicationEvent方法。getOrder方法,数字越小优先级越高。
注解实现
能用注解搞定的事,干嘛还要手写这么多代码呢,时间拿来摸鱼它不香吗。
我们把三个监听类放到一起
@Service
public class OpenDoorListener {
@Order(2)
@EventListener(classes = OpenDoorEvent.class)
public void openLight() {
System.out.println("step2:打开灯光...");
}
@Order(3)
@EventListener(classes = OpenDoorEvent.class)
public void openTV() {
System.out.println("step3:打开电视...");
}
@Order(1)
@EventListener(classes = OpenDoorEvent.class)
public void openKT() {
System.out.println("step1:打开空调...");
}
}
输出结果
欢迎主人回家...
step1:打开空调...
step2:打开灯光...
step3:打开电视...

浙公网安备 33010602011771号