java设计模式解析(1) Observer观察者模式

 
设计模式系列文章



java设计模式解析(1) Observer观察者模式
java设计模式解析(2) Proxy代理模式
java设计模式解析(3) Factory工厂模式
java设计模式解析(4) Singleton单例模式
java设计模式解析(5) Delegate委派模式
java设计模式解析(6) Strategy策略模式
java设计模式解析(7) Prototype原型模式
java设计模式解析(8) Template模版模式
java设计模式解析(9) Decorator装饰模式
java设计模式解析(10) Adapter适配模式
java设计模式解析(11)  Chain责任链模式
 

 

 

 

 

 

 

 

 

 

主要内容

 

 

1、简述

2、实现代码(Talk is cheap,Show me the code)

3、注意点

 

1、简述

 观察者设计模式在日常软件开发非常常见。比如MQ消息监听、ZooKeeper监听节点事件、Spring发布事件以完成容器初始化(后续会有分析)等。

 度娘上对观察者模式有很多版本定义,个人觉得还是《设计模式之禅》定义比较全面,不愧设计模式宝典啊。先贴出来具体定义:

 

针对上面给出的几个关键对角色,补充一下自己的理解:

1)、Subject:被观察者,即事件的起源。一般在软件实现阶段是 接口 或者 抽象类 

2)、Observer:观察者,即观察到事件发生则同步更新自身的状态。一般在软件实现阶段是 接口 或者 抽象类 

 

2、实现代码(Talk is cheap,Show me the code)

《设计模式之禅》已经给出具体的代码实现部分,但是个人觉得过于标准化,现实软件落地肯定会对其进行改造,例如Spring发布事件机制(后续会有分析)。这里个人实现场景,欢迎拍砖:

定义:大学每个学期都会提前订阅该学期的课程,一个课程会被N多个学生订阅。假设某个数学课程任课老师变更之后,学生需要同步更新课程信息,实现自级联变更。

分析:此时可以看出来【课程】就是被观察者的角色,【学生】就是观察者的角色。当【课程】有变动即任课老师变更,需要及时通知【学生】。

 Subject课程

/**
 * 课程 被观察的对象
 * @author  zhou.guangfeng on 2019/8/21 下午5:29
 */
public interface Subject {
    void teacherChange(String teacherName) ;
}

 Student学生

/**
 * 学生 观察者
 * @author  zhou.guangfeng on 2019/8/21 下午5:29
 */
public interface Student {
    void changeSubjectTeacherName(String teacherName) ;
}

 Observer监听 串联观察者 和 被观察者,同时实现被观察者接口

/**
 * 监听 串联观察者 和 被观察者。同时实现被观察者接口
 * @author  zhou.guangfeng on 2019/8/21 下午5:29
 */
public class Observer implements Subject {

    private Subject subject ;

    private List<Student> studentList = new ArrayList<>() ;

    public Observer(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void teacherChange(String teacherName) {
        subject.teacherChange(teacherName);
        studentList.forEach(student -> student.changeSubjectTeacherName(teacherName));
    }

    /**
     * 动态注册观察者
     *
     * @param
     * @return
     */
    public void registerStudent(Student student){
        System.out.println("动态注册观察者 --> " + student);
        studentList.add(student) ;
    }

    /**
     * 动态删除观察者
     *
     * @param
     * @return
     */
    public void removeStudent(Student student){
        System.out.println("动态删除观察者 --> " + student);
        studentList.remove(student) ;
    }

}

 ObserverMain执行代码

public class ObserverMain {

    public static void main(String[] args) {
        // 被观察者 数学课程
        Subject shuxue = new Subject() {
            @Override
            public void teacherChange(String teacherName) {
                System.out.println("数学课程 修改老师为 " + teacherName);
            }
        };

        // 监听者 代理了被观察者 即 数学课程
        Observer watcher = new Observer(shuxue) ;
        Student student = new Student() {
            @Override
            public void changeSubjectTeacherName(String teacherName) {
                System.out.println("学生A 修改老师为 " + teacherName);
            }
        } ;

        // 注册 观察者
        watcher.registerStudent(student);
        watcher.registerStudent(new Student() {
            @Override
            public void changeSubjectTeacherName(String teacherName) {
                System.out.println("学生B 修改老师为 " + teacherName);
            }
        });

        // 改变课程
        watcher.teacherChange("华罗庚");

        // 删除监听学生
        watcher.removeStudent(student);

        // 改变课程
        watcher.teacherChange("爱因斯坦");
    }
}

 执行结果: 

动态注册观察者 --> com.nancy.observer.ObserverMain$2@6f94fa3e
动态注册观察者 --> com.nancy.observer.ObserverMain$3@5e481248
数学课程 修改老师为 华罗庚
学生A 修改老师为 华罗庚
学生B 修改老师为 华罗庚
动态删除观察者 --> com.nancy.observer.ObserverMain$2@6f94fa3e
数学课程 修改老师为 爱因斯坦
学生B 修改老师为 爱因斯坦

 

3、注意点

(1)、由于触发观察者是顺序调用,如果观察者很多(例子中student群体特别多,触发时间很长)势必会有效率瓶颈,此时可以考虑使用线程池等异步进行。

(2)、关系广播链接不能太复杂,否则将难于维护。

 

posted on 2019-08-22 14:18  小猩  阅读(713)  评论(1编辑  收藏  举报

导航