事件处理模型
小朋友睡醒了就哭,饿
写程序模拟这个过程:
v1:最简单的就是写程序一直观察着,什么时候哭了就进行处理
/**
* 披着面向对象外衣的面向过程
*/
public class Main1 {
public static void main(String[] args) {
boolean cry = false;
while(!cry) {
//进行处理
}
}
}
v2: 面向对象,至少抽象出child类来:
/**
* 面向对象的傻等
* 一直观察,直到有线程调用了wakeUp方法
* 程序没写完,涉及到线程同步,没有写完
*/
class Child {
private boolean cry = false;
public boolean isCry() {
return cry;
}
public void wakeUp() {
System.out.println("Waked Up! Crying wuwuwuwu...");
cry = true;
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
while(!child.isCry()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("observing...");
}
}
}
v3: 加入观察者Dad到被观察者Child里面,什么时候醒了,直接调用观察者的方法
/**
* 加入观察者
*/
class Child {
private boolean cry = false;
private Dad d = new Dad(); //加入观察者Dad到被观察者Child里面
public boolean isCry() {
return cry;
}
public void wakeUp() {
cry = true;
d.feed(); // 直接调用观察者的方法
}
}
class Dad {
public void feed() {
System.out.println("dad feeding...");
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
//do sth
c.wakeUp();
}
}
v4:加入多个观察者,当一个事件发生的时候,每个观察者的处理方式不同
/**
* 加入多个观察者
*/
class Child {
private boolean cry = false;
// 多个观察者
private Dad dad = new Dad();
private Mum mum = new Mum();
private Dog dog = new Dog();
public boolean isCry() {
return cry;
}
public void wakeUp() {
cry = true;
// 每个观察者的处理方式不同
dad.feed();
dog.wang();
mum.hug();
}
}
class Dad {
public void feed() {
System.out.println("dad feeding...");
}
}
class Mum {
public void hug() {
System.out.println("mum hugging...");
}
}
耦合度太高,观察者的处理方法不一定只适合当前的被观察者,例如小狗汪汪叫这个出来方法,可能也适合于鸡叫的事件
而且添加新的观察者比较麻烦 --> 扩展性不好,耦合度高
v5:分离观察者与被观察者。定义一个Observer接口,里面有actionWeakup方法,指的是小孩醒了之后要采取的动作,不同的观察者实现这Observer个接口
/**
* 分离观察者与被观察者
*/
class Child {
private boolean cry = false;
// 将观察者放到list中
private List<Observer> observers = new ArrayList<>();
{
observers.add(new Dad());
observers.add(new Mum());
observers.add(new Dog());
}
public boolean isCry() {
return cry;
}
public void wakeUp() {
cry = true;
// 当wakeup事件发生的时候,遍历观察者进行处理
for(Observer o : observers) {
o.actionOnWakeUp();
}
}
}
// 定义一个Observer接口
interface Observer {
void actionOnWakeUp();
}
//不同的观察者实现这个Observer接口
class Dad implements Observer {
public void feed() {
System.out.println("dad feeding...");
}
@Override
public void actionOnWakeUp() {
feed();
}
}
class Mum implements Observer {
public void hug() {
System.out.println("mum hugging...");
}
@Override
public void actionOnWakeUp() {
hug();
}
}
class Dog implements Observer {
public void wang() {
System.out.println("dog wang...");
}
@Override
public void actionOnWakeUp() {
wang();
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
//do sth
c.wakeUp();
}
}
一个事件发生,会经过一系列的观察者的处理,这个事件才算完成
v5:一个事件发生之后,观察者需要根据事件的具体情况,做出处理。例如小孩哭的厉不厉害,时间等
该怎么把小孩哭的事件的具体情况传递给观察者呢?
封装一个事件类,事件的所有情况都在事件里面:
/**
* 有很多时候,观察者需要根据事件的具体情况来进行处理
*/
class Child {
private boolean cry = false;
private List<Observer> observers = new ArrayList<>();
{
observers.add(new Dad());
observers.add(new Mum());
observers.add(new Dog());
}
public boolean isCry() {
return cry;
}
public void wakeUp() {
cry = true;
// 醒了之后,创建一个事件对象
wakeUpEvent event = new wakeUpEvent(System.currentTimeMillis(), "bed");
// 事件对象传递给观察者
for(Observer o : observers) {
o.actionOnWakeUp(event);
}
}
}
//事件类 fire Event
class wakeUpEvent{
long timestamp;
String loc;
public wakeUpEvent(long timestamp, String loc) {
this.timestamp = timestamp;
this.loc = loc;
}
}
// 事件的所有情况都在事件里面,封装好传给观察者
interface Observer {
void actionOnWakeUp(wakeUpEvent event);
}
// Observer里面可以写if,判断event的情况,来进行处理,这块代码里面为了简便就没写
class Dad implements Observer {
public void feed() {
System.out.println("dad feeding...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
feed();
}
}
class Mum implements Observer {
public void hug() {
System.out.println("mum hugging...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
hug();
}
}
class Dog implements Observer {
public void wang() {
System.out.println("dog wang...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
wang();
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
//do sth
c.wakeUp();
}
}
观察者模式三要素:
Source事件源对象 --> 是谁发出的事件
Observer观察者 --> 是谁在等着这个事件
Event事件 --> 事件本身
事件源对象有一堆的观察者观察着它,当事件源对象发出事件的时候,观察者会对事件进行处理
V7:一个事件源可以发出不同的事件,一个事件也可以被多个观察者处理,大多数时候,我们处理事件的时候,需要事件源对象
为什么需要事件源对象:因为有时候需要根据事件源对象的不同,采用不同的处理方法。
Sping的AOP其实可以语义上理解成观察者模式,在程序执行的过程中,弄一个切面,当代码执行到这个切面的时候,先执行指定好的一系列方法,
然后继续往下,这就相当于观察者模式,观察着这个切面,当到达这个切面的时候,先执行一系列定义好的方法
/**
* 有很多时候,观察者需要根据事件的具体情况来进行处理
* 大多数时候,我们处理事件的时候,需要事件源对象
*/
class Child {
private boolean cry = false;
private List<Observer> observers = new ArrayList<>();
{
observers.add(new Dad());
observers.add(new Mum());
observers.add(new Dog());
}
public boolean isCry() {
return cry;
}
public void wakeUp() {
cry = true;
wakeUpEvent event = new wakeUpEvent(System.currentTimeMillis(), "bed", this);
for(Observer o : observers) {
o.actionOnWakeUp(event);
}
}
}
class wakeUpEvent{
long timestamp;
String loc;
// 将事件源对象,绑定到事件本身
Child source;
public wakeUpEvent(long timestamp, String loc, Child source) {
this.timestamp = timestamp;
this.loc = loc;
this.source = source;
}
// 往往事件对象都会有一个getSource方法,例如系统提供的WindowEvent
public Child getSource() {
return this.source;
}
}
interface Observer {
void actionOnWakeUp(wakeUpEvent event);
}
class Dad implements Observer {
public void feed() {
System.out.println("dad feeding...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
feed();
}
}
class Mum implements Observer {
public void hug() {
System.out.println("mum hugging...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
hug();
}
}
class Dog implements Observer {
public void wang() {
System.out.println("dog wang...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
wang();
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
//do sth
c.wakeUp();
}
}
v8:java里面的事件继承自EventObject这个类。
这里也自己定义了一个事件类,里面有getSource方法
钩子函数,hook,callback,listener都是观察者模式,都是一回事
/**
* 有很多时候,观察者需要根据事件的具体情况来进行处理
* 大多数时候,我们处理事件的时候,需要事件源对象
* 事件也可以形成继承体系
*/
class Child {
private boolean cry = false;
private List<Observer> observers = new ArrayList<>();
{
observers.add(new Dad());
observers.add(new Mum());
observers.add(new Dog());
// 钩子函数hook,钩在那里,当事件发生的时候,钩子函数被执行
// 钩子函数就是Observer模式
// 传过去的是个函数
observers.add((e)->{
System.out.println("ppp");
});
//hook callback function
}
public boolean isCry() {
return cry;
}
public void wakeUp() {
cry = true;
wakeUpEvent event = new wakeUpEvent(System.currentTimeMillis(), "bed", this);
for(Observer o : observers) {
o.actionOnWakeUp(event);
}
}
}
// 定义抽象Event方法,里面有getSource方法
abstract class Event<T> {
abstract T getSource();
}
class wakeUpEvent extends Event<Child>{
long timestamp;
String loc;
Child source;
public wakeUpEvent(long timestamp, String loc, Child source) {
this.timestamp = timestamp;
this.loc = loc;
this.source = source;
}
@Override
Child getSource() {
return source;
}
}
interface Observer {
void actionOnWakeUp(wakeUpEvent event);
}
class Dad implements Observer {
public void feed() {
System.out.println("dad feeding...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
feed();
}
}
class Mum implements Observer {
public void hug() {
System.out.println("mum hugging...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
hug();
}
}
class Dog implements Observer {
public void wang() {
System.out.println("dog wang...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
wang();
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
//do sth
c.wakeUp();
}
}
v9:java jwt里面用了观察者模式,点击button,所有的观察者listener会被触发
public class TestFrame extends Frame {
public void launch() {
Button b = new Button("press me");
b.addActionListener(new MyActionListener());
b.addActionListener(new MyActionListener2());
this.add(b);
this.pack();
this.addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
this.setLocation(400, 400);
this.setVisible(true);
}
public static void main(String[] args) {
new TestFrame().launch();
}
private class MyActionListener implements ActionListener { //Observer
public void actionPerformed(ActionEvent e) {
((Button)e.getSource()).setLabel("press me again!");
System.out.println("button pressed!");
}
}
private class MyActionListener2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("button pressed 2!");
}
}
}
jvm运行着,监听着操作系统的键盘事件,当按键发生的时候,jvm会创建好KeyEvent事件
js里面也有event对象,事件源对象是event.traget。当按下button的时候,会自动生成event对象,把事件源对象传过去
在很多系统中,Observer模式往往和责任链共同负责对于事件的处理,其中的某一个observer负责是否将事件进一步传递
Observer不存在往回传的情况 --> 责任链部分讲到