观察者模式
在观察者模式中,事件源,观察者,事件是一个组合。
事件源Source对象,拥有一堆Observer,然后他会发出一堆Event,Observer观察到Event之后会做出具体的反应。
问题
一个小孩,醒了会哭,需要有人照顾。
代码实现
版本一
- 面向过程
package com.cyc.design.observer.v1;
/**
* 披着面向对象外衣的面向过程
*/
public class Main1 {
public static void main(String[] args) {
boolean cry = false;
while(!cry) {
//对小孩哭这一事件进行处理
}
}
}
版本二
- 面向对象
package com.cyc.design.observer.v2;
/**
* 面向对象的傻等
*/
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...");
}
}
}
和版本一没有区别 ,本质上就是在等。
版本三
- 加入观察者Dad
package com.mashibing.dp.observer.v3;
/**
* 加入观察者
*/
class Child {
private boolean cry = false;
private Dad d = new Dad();
public boolean isCry() {
return cry;
}
public void wakeUp() {
cry = true;
//Dad 作为观察者,处理孩子哭的事件
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();
}
}
但是这种方式耦合度过高,不利于扩展
版本四
- 加入多个观察者,每个观察者都可以处理这件事,处理方式都不同
package com.mashibing.dp.observer.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...");
}
}
class Dog {
public void wang() {
System.out.println("dog wang...");
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
//do sth
c.wakeUp();
}
}
但是这种也不够灵活,假如观察者还要处理别的事件,例如,dog不止在小孩哭的时候叫,在看到陌生人的时候也会叫。那这种处理方式就无法满足此需求
也就是说观察者对于事件的反应不一定要耦合到某一个特定的观察对象上。
版本五
- 分离观察者与被观察者
任何一个观察者在小孩哭了之后,都要做出某些反应。所以这里定义一个观察类接口,其他观察者实现这个接口。小孩对象中也不再写死某个观察者,而是通过代码块的方式进行加载。而在wake方法中,通过遍历观察者的方式进行对该小孩哭这一事件的处理。这些observer其实就是多态的应用,和责任链模式相似。
package com.cyc.design.observer.v5;
import java.util.ArrayList;
import java.util.List;
/**
* 分离观察者与被观察者
*/
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;
for(Observer o : observers) {
o.actionOnWakeUp();
}
}
}
interface Observer {
void actionOnWakeUp();
}
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();
}
}
版本六
很多时候,观察者需要根据事件的具体情况做出反应,所以这里新建一个事件类,child负责发出这个事件, 将child醒了之后的所有状况封装到wakeUpEvent事件对象中。
package com.cyc.design.observer.v6;
import java.util.ArrayList;
import java.util.List;
/**
* 有很多时候,观察者需要根据事件的具体情况来进行处理
*/
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);
}
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();
}
}
版本七
大多数时候,我们处理事件的时候,需要知道事件源对象,观察者可以观察多个事件源,同样事件源也可以被多个观察者观察。此时事件对象中,就需要加入事件源对象了。
package com.cyc.design.observer.v7;
import java.util.ArrayList;
import java.util.List;
/**
* 有很多时候,观察者需要根据事件的具体情况来进行处理
* 大多数时候,我们处理事件的时候,需要知道事件源对象
*/
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;
}
}
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();
}
}
版本八
事件也可以形成继承体系
查看java内部的事件体系 , 如KeyEvent
EventObject就是所有事件的父类, 因此代码可以这样写
package com.cyc.design.observer.v8;
import java.util.ArrayList;
import java.util.List;
/**
* 有很多时候,观察者需要根据事件的具体情况来进行处理
* 大多数时候,我们处理事件的时候,需要事件源对象
* 事件也可以形成继承体系
*/
class Child {
private boolean cry = false;
private List<Observer> observers = new ArrayList<>();
{
observers.add(new Dad());
observers.add(new Mum());
observers.add(new Dog());
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);
}
}
}
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();
}
}
java本身观察者
package com.cyc.design.observer.v9;
import java.awt.Button;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class TestFrame extends Frame {
public void launch() {
//AWT 的一个类, 表示一个按钮
Button b = new Button("press me");
//当鼠标点到按钮上后 , 会产生这件事
b.addActionListener(new MyActionListener());
b.addActionListener(new MyActionListener2());
//将button放到窗口中
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();
}
//相当于Observer
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!");
}
}
}
运行一下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ob4KbmG0-1623307878801)(C:\Users\fei\AppData\Local\Temp\1623297971449.png)]
小测试
public class Test {
public static void main(String[] args) {
Button b = new Button();
b.addActionListener(new MyActionListener());
b.addActionListener(new MyActionListener2());
b.buttonPressed();
}
}
class Button {
private List<ActionListener> actionListeners = new ArrayList<ActionListener>();
public void buttonPressed() {
ActionEvent e = new ActionEvent(System.currentTimeMillis(), this);
for (int i = 0; i < actionListeners.size(); i++) {
ActionListener l = actionListeners.get(i);
l.actionPerformed(e);
}
}
public void addActionListener(ActionListener l) {
actionListeners.add(l);
}
}
interface ActionListener {
void actionPerformed(ActionEvent e);
}
/**
* 观察者1
*/
class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("button pressed!");
}
}
/**
* 观察者2
*/
class MyActionListener2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("button pressed 2!");
}
}
class ActionEvent {
//事件对象, 包含两个参数, 时间和事件源
long when;
Object source;
public ActionEvent(long when, Object source) {
super();
this.when = when;
this.source = source;
}
public long getWhen() {
return when;
}
public Object getSource() {
return source;
}
}
总结
Observer , listener, Hook, Callback , 这些都是观察者模式
在很多系统中,Observer模式往往和责任链共同负责对于事件的处理,
其中的某一个observer负责是否将事件进一步传递