常用的设计模式(笔记)——观察者

2022-03-17  本文已影响0人  红鲤鱼与绿鲤鱼与驴与鱼

个人理解:观察者就是当 对象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;
    }
}

上一篇下一篇

猜你喜欢

热点阅读