美文网首页
观察者模式

观察者模式

作者: LENN123 | 来源:发表于2020-04-20 11:57 被阅读0次

    前言

    观察者(Observer)模式是一种使用频率很高的设计模式,之前在介绍Javax.Servlet包下的Listener的时候,我们知道Listener能够在某一特定事件发生的时候(比如Servlet容器的创建和销毁)作出响应。为了完成这个功能,Listener就采用了观察者模式。

    场景

    假设我们现在有一个闹钟类Clock,当把它开启的时候它就会在一个特定的时间闹铃,如果类Son听到这个闹钟的铃声,就会起床去上学。为了模拟这个场景,我们可以简单的写下如下代码。

    • ClockSon
    class Clock {
        private volatile boolean ring;
        public void turnOn() {
            System.out.println("闹钟响了");
            ring = true;
        }
        public boolean isRing(){
            return ring;
        }
    }
    class Son {
        public void goToSchool(){
            System.out.println("孩子起床上学");
        }
    }
    
    • 测试类
    public class ObserverTest {
        public static Clock clock = new Clock();
        public static void main(String[] args) {
            Son son = new Son();
    
            new Thread(()->{
                try{
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                clock.turnOn();
            }).start();
    
            while (!clock.isRing()) {
                // wait
            }
            son.goToSchool();
        }
    }
    
    • 实验结果
    闹钟响了
    孩子起床上学
    
    Process finished with exit code 0
    

    这个实现方式很简单,Son一直轮询判断闹钟有没有响就可以了。缺点也很显然,沦陷的时候一直在空转,占用cpu时间,造成了资源浪费。那有什么办法可以不用空转去轮询状态呢?我们可以让闹钟闹铃的时候直接通知Son起来处理就好了,也就是让son监听clock转换为clock通知son

    • 优化-取消轮询
    class Clock {
        private volatile boolean ring;
        private Son son = new Son();
        public void turnOn() {
            System.out.println("闹钟响了");
            ring = true;
            son.goToSchool();
        }
        public boolean isRing(){
            return ring;
        }
    }
    

    现在我们把son捆绑在clock上,当clockturn on方法一调用就立刻调用songoToSchool()方法。现在可以说我们把son注册进了clock,使其成为clock的观察者。观察者模式到这里就结束了吗? 显然没有,考虑到我们对于一个事件并不是只有一个观察者,假设在这个场景下,闹钟一响,不仅儿子要起床上学,父亲也要起床上班,母亲则需要出门买菜,也就是说对于闹钟闹铃这个事件,有3个观察者,则上述代码要改成如下。

    • 添加的Father,Mather
    class Father {
        public void goToWork(){
            System.out.println("爸爸起床上班");
        }
    }
    class Mother {
        public void goBuyFood(){
            System.out.println("妈妈出门买菜");
        }
    }
    class Son {
        public void goToSchool(){
            System.out.println("孩子起床上学");
        }
    }
    
    • Clock
    class Clock {
        private volatile boolean ring;
        private Son son = new Son();
        private Father father = new Father();
        private Mother mother = new Mother();
        public void turnOn() {
            System.out.println("闹钟响了");
            ring = true;
            son.goToSchool();
            father.goToWork();
            mother.goBuyFood();
        }
        public boolean isRing(){
            return ring;
        }
    }
    

    添加了FatherMother类之后,我们还要把它们写死进Clock代码里,此外还要明确每个观察者需要被执行的方法。所有的观察者和Clock这个被观察对象紧紧的耦合在一起了。代码的扩展性特别差。何如修改才能让其真正成为观察者模式呢?我们知道约定优于配置,既然我们不知道每一个观察者需要被调用的具体方法,那我们就约定一个方法叫做doSomething(),所有的观察者只要实现某个接口实现该方法就可以了,此外有了这个接口,我们可以将所有的观察者对象看成一类,在被观察对象类中提供一个注册接口就可以了。让我们按照这个思路来进行优化。

    • 约定Observer接口
    interface Observer {
        public void doSomething();
    }
    
    
    • SonMotherFather类都来实现这个接口
    class Father implements Observer{
        public void goToWork(){
            System.out.println("爸爸起床上班");
        }
    
        @Override
        public void doSomething() {
            this.goToWork();
        }
    }
    
    class Mother implements Observer {
        public void goBuyFood(){
            System.out.println("妈妈出门买菜");
        }
    
        @Override
        public void doSomething() {
            goBuyFood();
        }
    }
    class Son implements Observer{
        public void goToSchool(){
            System.out.println("孩子起床上学");
        }
    
        @Override
        public void doSomething() {
    
        }
    }
    
    • 修改Clock类提供添加观察者方法
    class Clock {
        private volatile boolean ring;
        private List<Observer> observers = new ArrayList<>();
        public void addObserver(Observer observer){
            observers.add(observer);
        }
        public void turnOn() {
            System.out.println("闹钟响了");
            ring = true;
            for (Observer observer : observers) {
                observer.doSomething();
            }
        }
        public boolean isRing(){
            return ring;
        }
    }
    
    • 进行测试
    public class ObserverTest {
        public static Clock clock = new Clock();
        public static void main(String[] args) {
            
           clock.addObserver(new Son());
           clock.addObserver(new Father());
           clock.addObserver(new Mother());
           
           clock.turnOn();
    
        }
    }
    
    • 输出结果
    闹钟响了
    爸爸起床上班
    妈妈出门买菜
    

    相关文章

      网友评论

          本文标题:观察者模式

          本文链接:https://www.haomeiwen.com/subject/qrcnbhtx.html