关于Java观察者模式的一点思考

Java里面有个观察者模式,网上的相关介绍有很多,所以在这儿那种很官方很书面的话我就不贴过来了。尽量用说人话的方式表达一些自己对这个设计模式的思考。

顾名思义“观察者”模式应该是来实现“观察”或者“监听”用的,他比较多地被使用在一对多依赖的环境下,当其中的被依赖项中的某些值或属性发生改变时,依赖他的其他对象都会收到通知,并作出相应的改变。说人话就是:当一个大V发微博或者文章时,部分专门转载发布大V文章的白嫖们也会及时地收到“大V更新啦!”的消息,并自己做出相应的后续操作。

 emmm扯远了。。。

Java中观察者模式需要被观察者继承java.util.Observable类,需要观察者实现java.util.Observer接口。其中Observer接口中有一个update方法,它在被观察者的某些位置发生改变时会被自动调用。

说到这里,我想部分搞过Android或者Swing的小伙伴应该就很熟了,这可不就是Event事件和那些个Listener监听器吗!难道说。。。

是的没错!观察者模式的确可以实现这种事件机制。这里我们就做一个Event的小例子 ,尝试自己封装一个事件以及其相关的Listener。

首先我们准备一个继承自Observable的基础Event类,里面包含了notify、setEventListener、removeListener、removeAllListener四个基础方法,它们对Observable类中一些常用的方法进行了封装,分别能实现:告知监听器数据已刷新、添加监听器、移除监听器和移除所有监听器的功能。

/**
 * @Auther:zl
 * @Date:2018-08-22 09:20
 * @Description:自定义继承Observable类的基本Event类
 */
public class BaseEvent extends Observable {
    /**
     * 事件的生效时通知监听器动作
     *
     * @param message
     */
    public void notify(Object message) {
        this.setChanged();
        if (message!= null) {
            this.notifyObservers(message);
        } else {
            this.notifyObservers();
        }
    }

    /**
     * 添加监听器
     *
     * @param observer
     */
    public void setEventListener(Observer observer) {
        this.addObserver(observer);
    }

    /**
     * 删除监听器
     * @param observer
     */
    public void removeListener(Observer observer){
        this.deleteObserver(observer);
    }

    /**
     * 移除所有监听器
     */
    public void removeAllListener(){
        this.deleteObservers();
    }
}

 

有了事件,那我们还需要一个监听器。

/**
 * @Auther:zl
 * @Date:2018-08-22 09:38
 * @Description:实现Observer接口的自定义监听器类
 */
public abstract class BaseEventListener implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        doAction(o, arg);
    }

    /**
     * 自己实现具体操作
     *
     * @param o
     * @param arg
     */
    public abstract void doAction(Observable o, Object arg);
}

这里就很简单了,因为考虑到监听器可能在实际应用中有着千奇百怪的用法,因此我们就用一个抽象类实现Observer接口,然后预留一个doAction抽象方法作为扩展,当监听器收到消息自动调用update方法时,可以使用我们自定义的方法去实现我们想要的功能。

有了两个基础类,那么我们现在写俩具体的实现类。

    /**
     * 自定义MoveEvent类,继承自基础事件类,能完成“移动”操作
     */
    static class MoveEvent extends BaseEvent {
        public boolean isMove = false;
        private int x, y;

        public void move(int x, int y) {
            this.x = x;
            this.y = y;

            if (x == 6) {
                //测试不同情况时,Listener的执行情况
                isMove = false;
            } else {
                isMove = true;
            }
            String msg = "坐标:(" + getX() + "," + getY() + ")";
            //发送消息
            notify(msg);
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }
    }

这里我们简单构造了一个MoveEvent类继承BaseEvent,这个事件能表示人物的移动情况。

因为在Listener中,我们可以根据一定条件来区分、筛选接收到的消息,从而做出不同的动作,所以这里为了测试,就以x==6为条件,当x=6时,就将移动标记(isMove)设置为false,表示未进行移动。

接下来,在main中我们可以写下测试方法:

public static void main(String[] args) {
        // 实例化MoveEvent
        MoveEvent event = new MoveEvent();
        // 给事件添加监听器
        event.setEventListener(new BaseEventListener() {
            // 重写doAction抽象方法,实现自定义功能。
            @Override
            public void doAction(Observable o, Object arg) {
                MoveEvent move = (MoveEvent) o;
                if (move.isMove) {
                    System.out.println(arg);
                }else {
                    System.out.println("未进行移动!");
                }
            }
        });

        //放在循环中,模拟人物移动
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(1000);
                event.move(i, i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

这里需要解释一下doAction方法中的两个参数:

 因为这里我们将Object当成消息直接输出了,所以在进行有需要根据不同条件进行处理时,我们可以使用Observable对象中的一些其他特殊标记作为判断依据。当然啦,如果将Object当成是特征值进行判断的话也是可以的~

  • Observable表示被监听对象
  • Object表示被监听对象发送的消息或传来的特征值 

运行结果如下:

从结果中我们可以看出,当x=6时,Listener按照我们预期的情况进行了不同的动作 。

到目前为止,我们自定义的事件及监听器就完成了!理论上来讲后续我们仅需要对两个基类进行不同程度的包装,就能实现各种不同的事件以及监听器的效果啦~

猜你喜欢

转载自blog.csdn.net/acevd/article/details/81938897