• 初识设计模式(观察者模式)


    前言:总结这两天学到的观察者模式,并用java小小的实现一下。

    什么是观察者模式?

    定义:观察者模式定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

    使用的设计原则:为了交互对象之间的松耦合设计而努力。

    代表:MVC

    类图

    观察者模式的优缺点?

      优点:解除观察者和通知者的耦合,让耦合双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。这也是体现了依赖倒转的原则。

      缺点

    1. 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
    2. 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进  行循环调用,可能导致系统崩溃。
    3. 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

    什么情况下使用观察者模式?

      当一个对象的改变需要使用同时改变其他对象的时候,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。

      注意:有多个观察者时,不可以依赖特定的通知顺序。 

    举例说明(自定义的方式实现观察者模式)

       场景:自习课上玩手机,需要防止班主任突然闯入,这时同学们派出一人来在门口守着, 一旦班主任来了,则通知所有玩手机的同学。

      采用设计模式:使用观察者模式来实现,因为一旦老师来了,玩手机的同学需要知道这件事,而且同学们也不关心被通知顺序。

      实现:门口守着的那位同学是通知者,玩手机的同学是观察者。

    •   首先创建通知者:
     1 /**
     2  * 守着门口的同学;抽象通知者
     3  */
     4 interface Subject{
     5     void registerObserver(Observer o);
     6 
     7     void removeObserver(Observer o);
     8 
     9     void notifyObservers(String tips);
    10 }
    11 
    12 /**
    13  * 具体的通知者
    14  */
    15 class StudentSubjet implements Subject{
    16 
    17     private List<Observer> observerList = new ArrayList<>();
    18 
    19     @Override
    20     public void registerObserver(Observer o) {
    21         observerList.add(o);
    22     }
    23 
    24     @Override
    25     public void removeObserver(Observer o) {
    26         observerList.remove(o);
    27     }
    28 
    29     @Override
    30     public void notifyObservers(String tips) {
    31         for(Observer observer : observerList){
    32             observer.update(tips);
    33         }
    34     }
    35 
    36     /**
    37      * 设置老师来了
    38      */
    39     public void setTeacherComing(String tips){
    40         notifyObservers(tips);
    41     }
    42 }
    •   然后创建观察者:
     1 /**
     2  * 玩手机的同学;抽象观察者
     3  */
     4 interface Observer{
     5     void update(String tips);
     6 }
     7 
     8 /**
     9  * 具体观察者小明
    10  */
    11 class XiaoMingObserver implements Observer{
    12     private Subject subject;
    13     XiaoMingObserver(Subject subject){
    14         this.subject = subject;
    15         this.subject.registerObserver(this);
    16     }
    17     @Override
    18     public void update(String tips) {
    19         System.out.println(tips + "小明知道了。");
    20     }
    21 }
    22 
    23 /**
    24  * 具体观察者小红
    25  */
    26 class XiaoHongObserver implements Observer{
    27     private Subject subject;
    28     XiaoHongObserver(Subject subject){
    29         this.subject = subject;
    30         this.subject.registerObserver(this);
    31     }
    32     @Override
    33     public void update(String tips) {
    34         System.out.println(tips + "小红知道了。");
    35     }
    36 }
    •   然后客户端实现:
     1  /**
     2      * 客户端代码
     3      * @param args
     4      */
     5     public static void main(String[] args){
     6         StudentSubjet studentSubjet = new StudentSubjet();
     7         XiaoMingObserver xiaoMingObserver = new XiaoMingObserver(studentSubjet);
     8         XiaoHongObserver xiaoHongObserver = new XiaoHongObserver(studentSubjet);
     9 
    10         studentSubjet.setTeacherComing("老师来了!");
    11         studentSubjet.setTeacherComing("老师走了!");
    12 
    13         studentSubjet.removeObserver(xiaoMingObserver);
    14         studentSubjet.setTeacherComing("第二次老师来了!");
    15     }
    •   最后输出:

    举例说明(java.util 的方式实现观察者模式)

      场景同前面一致,只是需要了解一下Observable的源代码。

    •   首先创建通知者:
     1 /**
     2  * 具体通知者
     3  */
     4 class StudentObservable extends Observable{
     5     private String tips;
     6     public void setTeacherComing(String tips){
     7         this.tips = tips;
     8         setChanged();//表示状态已经改变
     9         notifyObservers(tips);
    10     }
    11 
    12     public String getTips() {
    13         return tips;
    14     }
    15 }
    •   然后创建观察者: 
    /**
     * 具体观察者小花
     */
    class XiaoHuaObserver implements Observer{
        private Observable observable;
    
        XiaoHuaObserver(Observable observable){
            this.observable = observable;
            this.observable.addObserver(this);
        }
    
        @Override
        public void update(Observable o, Object arg) {
            if(o instanceof StudentObservable){
                StudentObservable studentObservable = (StudentObservable) o;
                System.out.println(studentObservable.getTips() + "小花知道了。");
            }
        }
    }
    /**
     * 具体观察者张三
     */
    class ZhangSanObserver implements Observer{
        private Observable observable;
    
        ZhangSanObserver(Observable observable){
            this.observable = observable;
            this.observable.addObserver(this);
        }
    
        @Override
        public void update(Observable o, Object arg) {
            if(o instanceof StudentObservable){
                StudentObservable studentObservable = (StudentObservable) o;
                System.out.println(studentObservable.getTips() + "张三知道了。");
            }
        }
    }
    •   然后客户端实现:
    /**
         * 客户端代码
         * @param args
         */
        public static void main(String[] args){
            StudentObservable studentObservable = new StudentObservable();
            XiaoHuaObserver xiaoHuaObserver = new XiaoHuaObserver(studentObservable);
            ZhangSanObserver zhangSanObserver = new ZhangSanObserver(studentObservable);
    
            studentObservable.setTeacherComing("老师来了!");
            studentObservable.setTeacherComing("老师走了!");
    
            studentObservable.deleteObserver(zhangSanObserver);
    
            studentObservable.setTeacherComing("第二次老师来了!");
        }
    •   最后输出:

    总结:两种实现方式

    1. 两种实现方式的输出的顺序不同,因为notify方法的实现不一致而已。
    2. java.util.Observable是一个类,必须设计一个类来继承它,就不能继承其他的类,这违反了设计原则多用组合,少用继承。
    3. 自定义的方式每次状态变化都会数据给观察者,而java.util.Observable可以实现观察者数据

    参考书籍:《Head First 设计模式》《大话设计模式》

  • 相关阅读:
    css3实现文本渐变
    元组--购物车实战
    js事件冒泡
    openssl生成v3版自签证书
    linux中可以在哪些地方增加环境变量
    linux下如何找到USB转串口
    linux下通过shell命令测试串口
    CANopen协议
    ubuntu使用虚拟can(vcan)
    移植python3到flash有限的arm
  • 原文地址:https://www.cnblogs.com/yuxiaole/p/9218050.html
Copyright © 2020-2023  润新知