个人理解:观察者就是当 对象A触发某个事件时 调用对象B 的方法,这种的就是观察者
举例:现在有一孩子(Child)在睡觉,当孩子醒来时通知父母(Mom 和 Dad)做一些事情,其中孩子是被观察者 父母是观察者
先定义一个观察者接口,观察者就是通过这个方法来观察 被观察者,换句话说就是被观察者调用观察者 doSomething
方法来通知他们
/**
* 抽象的观察者
* 观察者需要实现的接口
*/
interface Observer {
void doSomething(WakeupEvent event);
}
具体的观察者,都需要实现Observer接口
/**
* 具体的观察者
*/
public class Dad implements Observer{
public void playGame(){
System.out.println("打游戏");
}
@Override
public void doSomething(WakeupEvent event) {
System.out.println("哪个事件源发出的:" + event.getSource().getClass());
System.out.println("爸爸:孩子醒了就去打游戏");
playGame();
}
}
/**
* 具体的观察者
*/
public class Mom implements Observer {
public void nurse() {
System.out.println("给孩子喂奶");
}
@Override
public void doSomething(WakeupEvent event) {
System.out.println("哪个事件源发出的:" + event.getSource().getClass());
System.out.println("妈妈:孩子醒了就喂奶");
nurse();
}
}
接下来就是被观察者,被观察者(Child) 是需要持有 观察者对象(Mom、Dad) 实例的
/**
* 这是被观察者
*/
public class Child {
/**
* 存放具体的观察者,可能被多个人观察所以用 List
*/
private ArrayList<Observer> observers = new ArrayList<>();
/**
* 添加观察者
*
* @param observer 具体的观察者
*/
public void addObserver(Observer observer) {
observers.add(observer);
}
/**
* 孩子醒了
*/
public void wakeUp() {
long time = System.currentTimeMillis();
Date date = new Date(time);
WakeupEvent event = new WakeupEvent(date.getTime(), "床上", this);
//通知观察者
observers.forEach(observer -> {
observer.doSomething(event);
});
}
}
还有一个类就是WakeupEvent
,这个类是干什么的呢?
这是一个事件类,根据面向对象的原则 被观察者 与 观察者 之间通过这个对像来传递参数,当然如果不用这个类的话,那doSomething
这个方法就要多传几个参数,比如 几点醒来的,在哪醒的,醒来后是个什么状态(哭、闹、笑)等等,所以要封装成对象
注意 private Child source;
这句话,为什么会有这个,因为当被观察者收到 WakeupEvent
对象时需要知道是哪个被观察者,观察者不可能只观察一个东西(或事物)
/**
* 事件对象
* 作用:被观察者发出此事件让观察者来接收并处理
*/
public class WakeupEvent {
private long time;
private String location;
//事件源对象,将事件源对象传递给观察者
private Child source;
public WakeupEvent(long time, String location, Child source) {
this.time = time;
this.location = location;
this.source = source;
}
public long getTime() {
return time;
}
public String getLocation() {
return location;
}
public Child getSource() {
return source;
}
}
最后让孩子添加被观察者并执行 醒来(wakeUp()
)方法
public class Main {
public static void main(String[] args) {
Child child = new Child();
//添加观察者
child.addObserver(new Mom());
child.addObserver(new Dad());
//
child.wakeUp();
}
}
输出如下:
哪个事件源发出的:class observer.study_01.Child
妈妈:孩子醒了就喂奶
给孩子喂奶
哪个事件源发出的:class observer.study_01.Child
爸爸:孩子醒了就去打游戏
打游戏
略微优化:
我们可以有自己的事件体系,看一下Android中的事件是怎么做的,以onTouchEvent为例,MotionEvent也包含着事件源对象
@Override
public boolean onTouchEvent(MotionEvent event) {
event.getSource();//事件源对象
return super.onTouchEvent(event);
}
MotionEvent.java
这个事件类继承了InputEvent
public final class MotionEvent extends InputEvent implements Parcelable {
}
InputEvent.java
这是一个抽象类,里面有个抽象方法getSource(),不过他的返回值是int 我们可以用泛型T来代替,
public abstract class InputEvent implements Parcelable {
public abstract int getSource();
}
注意什么时候该用抽象类,什么时候该用接口?
名词 用抽象类,动词用接口
新建一个所有事件的父类
/**
* 所有事件的父类
* @param <T> 事件源
*/
public abstract class Event<T> {
abstract T getSource();
}
让我们之前的·WakeupEvent.java
继承他
/**
* 事件对象
* 作用:被观察者发出此事件让观察者来接收并处理
*/
public class WakeupEvent extends Event<Child> {
private long time;
private String location;
//事件源对象,将事件源对象传递给观察者
private Child source;
public WakeupEvent(long time, String location, Child source) {
this.time = time;
this.location = location;
this.source = source;
}
public long getTime() {
return time;
}
public String getLocation() {
return location;
}
@Override
Child getSource() {
return source;
}
}
网友评论