• Java设计模式(17)——行为模式之观察者模式(Observer)


    一、概述

      概念

      

       UML简图

      

       我们根据一个示例得类图来分析角色

      

      角色

      抽象主题:保存观察者聚集(集合),管理(增删)观察者

      抽象观察者:定义具体观察者的抽象接口,在得到主题通知后更新自己

      具体主题:将有关状态存入具体观察者,状态发生改变时,通知观察者

      具体观察者:存储与主题角色自洽的状态

    二、实践

      我们先将上面的示例图使用Java代码实现,再讨论Java中的观察者

      抽象主题

    /**
     * 抽象主题接口
     *
     * @author Administrator
     **/
    public interface Subject {
        /**
         * 登记/增加一个观察者
         * @param observer 新增的观察者
         */
        void attach(Observer observer);
    
        /**
         *删除一个观察者
         * @param observer 删除的观察者
         */
        void detach(Observer observer);
    
        /**
         * 通知观察者
         */
        void notifyObserver();
    }

      具体主题——可以注意复习我们之前学习的拉姆达表达式

    /**
     * 具体主题角色
     *
     * @author Administrator
     **/
    public class ConcreteSubject implements Subject{
        private List<Observer> observerList = new LinkedList<>();
        @Override
        public void attach(Observer observer) {
            observerList.add(observer);
        }
    
        @Override
        public void detach(Observer observer) {
            observerList.remove(observer);
        }
    
        @Override
        public void notifyObserver() {
            // 遍历通知观察者(可以使用聚集的拷贝防止外部的修改)
            for (Observer observer : observerList) {
                observer.update();
            }
            // Java8写法
    //        observerList.forEach((observer)-> observer.update());
    //        observerList.forEach(Observer::update);
        }
    }

      抽象观察者

    /**
     * 观察者接口
     *
     * @author Administrator
     **/
    public interface Observer {
        /**
         * 收到通知的更新操作
         */
        void update();
    }

      具体观察者

    /**
     * 具体观察者
     *
     * @author Administrator
     **/
    public class ConcreteObserver implements Observer{
        @Override
        public void update() {
            // 更新的逻辑
        }
    }

      当然,我们也可以改成第二种方案,将抽象主题改成抽象类,这样就可以由抽象角色来持有观察者的聚集引用,而且管理聚集的增删方法也可以直接在

    抽象主题中直接实现,这样子类只需要很轻量级的代码了:

      

      有了上面的基础,我们来看Java对观察者的原生支持:

      Java的API还为为我们提供现成的Observer接口Java.util.Observer。我们只要直接使用它就可以。

      先看这个Observer接口:

      

      这个接口比较简单,我们直接看陌生的面孔——update()的参数类型:Observable,看它的介绍:

      

      

       看完文字的介绍我们也可以通过查看源码更加清晰的认识这个类

      接下来我们举一个栗子:假设一个商品的价格变更了应该通知它的观察者:——使用的是UML简图的方案二

      被观察者,产品:

    /**
     * 具体被观察者
     *
     * @author Administrator
     **/
    public class Product extends Observable{
        private String name;
        private float price;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
            // 设置通知
            setChanged();
            notifyObservers(name);
        }
    
        public float getPrice() {
            return price;
        }
    
        public void setPrice(float price) {
            this.price = price;
            setChanged();
            notifyObservers(new Float(price));
        }
    }

      两个观察者:

    /**
     * name观察者
     *
     * @author Administrator
     **/
    public class NameObserver implements java.util.Observer{
        @Override
        public void update(Observable o, Object arg) {
            System.out.println(o);
            String name;
            if (arg instanceof String) {
                name = (String) arg;
                // 变更的逻辑
                System.out.println("产品名称已经变更为:" + name);
            }
        }
    }

      

    /**
     * price观察者
     *
     * @author Administrator
     **/
    public class PriceObserver implements java.util.Observer{
        @Override
        public void update(Observable o, Object arg) {
            System.out.println(o);
            float price;
            if (arg instanceof Float) {
                // 变更逻的辑
                price = (Float) arg;
                System.out.println("产品价格变更为:" + price);
            }
        }
    }

      客户端:

    /**
     * 客户端
     * @author  Administrator
     **/
    public class Client {
        public static void main(String[] args) {
            // 下面调用了新增的方法,无法使用多态声明
            Product product = new Product();
            java.util.Observer nameObserver = new NameObserver();
            java.util.Observer priceObserver = new PriceObserver();
    
            // 增加观察者
            product.addObserver(nameObserver);
            product.addObserver(priceObserver);
    
            product.setName("小西瓜");
            product.setPrice(100.1f);
        }
    }

      

      // 这里第一个未使用到的参数就是抽象被观察者了,当然这里由于产品子类有新增方法,故不能调用新增方法

      而且,这里是通知了所有的观察者

  • 相关阅读:
    Dockershim 即将被移除?看 SUSE Rancher 的应对之道!
    使用 Rancher 进行首次金丝雀部署
    cOStoolkit:Container OS 的下一程
    如何在 K3s 中启用 Traefik Dashborad
    如何使用 Rancher Desktop 访问 Traefik Proxy 仪表板
    如何使用国内资源在 RKE2 上安装 Rancher HA
    Rancher 2.6 全新 Logging 快速入门
    实用教程 | 云原生安全平台 NeuVector 部署
    一文玩儿转 Rancher Desktop
    学多少年才算“精通Java”?
  • 原文地址:https://www.cnblogs.com/jiangbei/p/7761427.html
Copyright © 2020-2023  润新知