设计模式Observer 观察者模式浅析

Posted 行百里er

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式Observer 观察者模式浅析相关的知识,希望对你有一定的参考价值。

Observer模式:事件处理模型

事件处理模型经常使用Observer+责任链

军情观察室

朝鲜生气了,后果不太严重。中美俄等对朝鲜暗中观察,就朝鲜的一系列活动各自采取措施。

被观察者朝鲜周围,有多双眼睛正观察着它呢,这些观察者有中国、美国、俄罗斯等等。。

当朝鲜有活动时,这些观察者会采取相应的活动。

用代码构造一下这个场景:

public class Client {
    public static void main(String[] args) {
        Korea k = new Korea();
        k.fire();
    }
}

class Korea {

    China china = new China();
    Usa usa = new Usa();

    public void fire () {
        System.out.println("朝鲜:发射核弹!");
        china.warn();
        usa.threaten();
    }
}

class China {
    public void warn () {
        System.out.println("中国:不要在我家门口玩火,否则后果自负!");
    }
}

class Usa {
    public void threaten () {
        System.out.println("美国:韩国小老弟来我们军事演练走一波!");
    }
}

运行结果:

朝鲜:发射核弹!
中国:不要在我家门口玩火,否则后果自负!
美国:韩国小老弟来我们军事演练走一波!

上面这段代码的弊端是显而易见的,因为这里的观察者不止中国、美国,还有日本、俄罗斯等等,如果继续加入观察者,将会在被观察者类Korea中继续添加代码,耦合度太高,不易扩展!

观察者模式

上面的模型其实就用到了观察者模式的思想,观察者针对被观察者的行为动作做出相应的处理。

由于耦合度高,我们可以分离观察者和被观察者。有很多时候,观察者需要根据事件的具体情况来进行处理,而且我们处理事件的时候,需要事件源对象。

观察者中国、美国等需要对被观察者朝鲜的具体动作时间进行处理,朝鲜就是发出事件的事件源对象。

代码升级了:

public class Client {
    public static void main(String[] args) {
        Korea k = new Korea();
        k.fire();
    }
}

class Korea {

    private List<Observer> observers = new ArrayList<>();
    {
        observers.add(new China());
        observers.add(new Usa());
    }

    public void fire () {
        System.out.println("朝鲜:我要发射了!Boom!!!");
        //事件发生了
        FireEvent fireEvent = new FireEvent(System.currentTimeMillis(), "夏威夷"this);
        observers.forEach(observer -> observer.onFire(fireEvent));
    }
}

/**
 * 抽象出事件类
 * @param <T>
 */

abstract class Event<T{
    abstract T getSource();
}

/**
 * 发射核弹事件,事件源是Korea
 */

class FireEvent extends Event<Korea{

    //事件发生时间
    long timestamp;
    //事件发生地点
    String location;
    //事件源
    private Korea korea;

    public FireEvent(long timestamp, String location, Korea korea) {
        this.timestamp = timestamp;
        this.location = location;
        this.korea = korea;
    }

    @Override
    public Korea getSource() {
        return korea;
    }
}

/**
 * 观察者
 */

interface Observer {
    //观察者根据事件作出响应
    void onFire(FireEvent fireEvent);
}

class China implements Observer {
    public void warn () {
        System.out.println("中国:不要在我家门口玩火,否则后果自负!");
    }

    @Override
    public void onFire(FireEvent fireEvent) {
        if (fireEvent.location.contains("鸭绿江")) {
            warn();
        }
    }
}

class Usa implements Observer {
    public void threaten () {
        System.out.println("美国:韩国小老弟来我们军事演练走一波!");
    }

    @Override
    public void onFire(FireEvent fireEvent) {
        if (fireEvent.location.contains("夏威夷")) {
            threaten();
        }
    }
}

运行结果:

朝鲜:我要发射了!Boom!!!
美国:韩国小老弟来我们军事演练走一波!

可以看到,观察者只根据事件源Korea的事件发射,位置夏威夷做出了时间响应!

而且,有没有发现,被观察者里面有一个List<Observer> observers,很像责任链模式对吧?观察者模式的事件处理模型通常是Observer+责任链的。

随处可见的观察者

javascript的onclick

<script>
 function cb(event){
  alert(event);
 }
</script>

<input type="button" onclick="cb(this)" value="点我!" />

监听点击事件,做出事件响应

jdk awt包下的Button等

public class MyFrame 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(400400);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        new MyFrame().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!");
        }

    }
}
【设计模式】Observer 观察者模式浅析

这里的ActionListener就是观察者。

我们平时遇到的钩子函数,回调函数,Observer,甚至一些Listener,其实都是观察者模式的体现。

观察者模式的通用类图

参考《设计模式之禅》

  • Subject被观察者

定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。

  • Observer观察者

观察者接收到消息后,即进行update(更新方法)操作,对接收到的信息进行处理。

  • ConcreteSubject具体的被观察者

定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。

  • ConcreteObserver具体的观察者

每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。

小结

  • 观察者模式是松偶合的。改变主题或观察者中的一方,另一方不会受到影响。
  • JDK中也有自带的观察者模式。但是被观察者是一个类而不是接口,限制了它的复用能力。

Observer

java.util

public interface Observer

A class can implement the Observer interface when it wants to be informed of changes in observable objects.

void update(Observable o, Object arg)

Observable

java.util

Class Observable

  • 在JavaBean和Swing中也可以看到观察者模式的影子。





熬夜不易,欢迎关注转发、点赞、在看,给个鼓励,谢谢大伙!

也欢迎多踩踩我的博客:https://blog.csdn.net/hundred_li_journey


以上是关于设计模式Observer 观察者模式浅析的主要内容,如果未能解决你的问题,请参考以下文章

[Android&amp;Java]浅谈设计模式-代码篇:观察者模式Observer

观察者模式(Observer Pattern)

设计模式之- 观察者模式(Observer Pattern)

JDK自带的Observable和Observer实现观察者模式

JAVA观察者模式(observer pattern)

行为类模式:观察者(Observer)