当前位置 博文首页 > 阳阳的博客:【设计模式】观察者模式

    阳阳的博客:【设计模式】观察者模式

    作者:[db:作者] 时间:2021-08-14 21:03

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?观察者模式

    定义

    ? ? ? ? 简而言之,观察者模式定义了对象间一种一对多的依赖关系,当某个对象发生状态的变化后,任何关注此对象的观察者会得到通知。观察者模式也成订阅/发布模型,当csdner订阅了该博主,那么当该博主发布一篇博文后,csdner将收到博文的推送,csdner将抽空阅读该篇博文,甚至点击关注。(你们懂吧,疯狂暗示)。


    简单实例

    ? ? ? ? 以一个简单的例子来说明观察者模式是如何运作的,具体场景如下:

    ? ? ? ? 在一个炎热的午后,主人正懒散的躺在躺椅上,尽情地感受阴凉。突然远处的流浪狗恶狠狠地叫了几声,猫听到后害怕极了,也叫了几声,主人听到狗叫声和猫叫声,以为发生了什么事情,便从躺椅上起来看看咋回事。此时躲在角落里的老鼠也听到了猫叫声,窜来窜去。

    ? ? ? ? 在这个例子中,狗是被观察者,猫既是观察者也是被观察者,主人和老鼠则是观察者。


    代码示例

    ? ? ? ? 项目的类图如下:

    ? ? ? ? 我们将被观察者的职责抽象成Subject,在这个类中,需要保存关注该被观察者的观察者集合,以及增加、删除观察者的方法,以及最重要的通知方法。任何被观察者都需要继承此类,这样只去考虑自己的逻辑方法即可。

    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 被观察者的职责
     */
    public class Subject {
    
        private List<Observer> observers = new ArrayList<>();
    
        public void addObserver(Observer o) {
            observers.add(o);
        }
    
        public void removeObserver(Observer o) {
            observers.remove(o);
        }
    
        public void notifyObservers() {
            for (Observer observer:observers) {
                observer.update(this);
            }
    
        }
    }
    

    ? ? ? ? 将观察者的职责抽象成Observer接口,任何观察者都需要实现此接口。在该接口中,提供update方法,用于在接收到通知后,执行相应的处理方法。

    /**
     * 观察者接口
     */
    public interface Observer {
    
        void update(Subject s);
    }
    

    ?

    ? ? ? ? 其中狗作为被观察者:

    /**
     * 狗仅是被观察者
     */
    public class Dog extends Subject {
    
        public void bark() {
            System.out.println("狗叫了几声");
            super.notifyObservers();
        }
    
    }
    

    ? ? ? ? 猫既是被观察者也是观察者:

    /**
     * 猫即是被观察者,也是观察者。
     * 猫被主人和老鼠观察,猫观察狗
     */
    public class Cat extends Subject implements Observer {
    
        public void scream() {
            System.out.println("猫叫了几声");
            super.notifyObservers();
        }
    
        @Override
        public void update(Subject s) {
            if (s instanceof Dog) {
                System.out.println("猫听到了狗叫声,害怕得叫了起来");
                scream();
            }
        }
    }
    

    ? ? ? ? 老鼠是观察者:

    /**
     * 老鼠仅是观察者
     */
    public class Mouse implements Observer {
    
        @Override
        public void update(Subject s) {
            if (s instanceof Cat) {
                System.out.println("老鼠听到猫叫声,撒腿就跑");
            }
        }
    }
    

    ? ? ? ? 主人是观察者:

    /**
     * 主人仅是观察者
     */
    public class Person implements Observer {
    
        public void update(Subject s) {
            if (s instanceof Dog) {
                System.out.println("主人听到狗叫声,过去看看情况");
            } else if (s instanceof Cat) {
                System.out.println("主人听到猫叫声,过去看看情况");
            }
        }
    
    }

    ? ? ? ? 运行类:

    /**
     * 2019/7/23 16:00
     * 观察者模式
     * 猫和主人观察狗,老鼠和主人观察猫
     */
    public class Main {
        public static void main(String[] args) {
            Dog dog = new Dog();
            Cat cat = new Cat();
            Mouse mouse = new Mouse();
            Person person = new Person();
            
            dog.addObserver(cat);
            dog.addObserver(person);
            cat.addObserver(mouse);
            cat.addObserver(person);
    
            dog.bark();
        }
    
    }
    

    ? ? ? ? 运行结果:


    其他说明

    ? ? ? ? 关于抽象类Subject与接口Observer,在java.util包中已经有对应的类。其中这里的Subject(可扩展的被观察者职责类)对应util包下的Observable类,该类提供了线程同步的实现。这里的Observer(观察者接口)对应util包下的Observer接口,两个接口内的方法并没有多大区别。

    ? ? ? ??

    cs