zoukankan      html  css  js  c++  java
  • 设计模式之观察者模式

    当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。

    一、介绍

    意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

    主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作

    关键字

    Observable

    即被观察者,也可以被叫做主题(Subject)是被观察的对象。通常有注册方法(register),取消注册方法(remove)和通知方法(notify)。

    Observer

    即观察者,可以接收到主题的更新。当对某个主题感兴趣的时候需要注册自己,在不需要接收更新时进行注销操作。

    二、代码示例

    举一个生活中的例子:比如用户从报社订阅报纸,报社和用户之间是一对多依赖,用户可以在报社订阅(register)报纸,报社可以把最新的报纸发给用户(notify),用户自动收到更新。在用户不需要的时候还可以取消注册(remove)。

    1. 首先我们抽象出一个报纸实体
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class NewsModel {
        String title;
        String content;
    }
    
    1. 定义一个被观察者(Subject)和观察者接口,
    /**
     * 被观察者接口定义
     */
    public interface MyObserverable {
    
        void register(MyObserver myObserver);
    
        void remove(MyObserver myObserver);
    
        void send(NewsModel model);
    
    }
    
    /**
     * 观察者接口定义
     */
    public interface MyObserver {
    
        void receive(NewsModel model);
    
    }
    
    1. 用户抽象
    /**
     * 对于用户的抽象
     */
    public class User implements MyObserver {
        private String mName;
    
        public User(String name) {
            mName = name;
        }
    
        @Override
        public void receive(NewsModel model) {
            System.out.println(mName + " receive news:" + model.getTitle() + "  " + model.getContent());
        }
    }
    
    1. 报社抽象
    /**
     * 对于报社的抽象,实现了被观察者接口,每隔5s发送一次报纸
     */
    public class NewsProvider implements MyObserverable {
        private static final long DELAY = 2 * 1000;
        private List<MyObserver> mObservers; //我们用一个List来维护所有的观察者对象
    
        public NewsProvider() {
            mObservers = new ArrayList<>();
            generateNews();
        }
    
        /**
         * 模拟产生新闻,每隔5s发送一次
         */
        private void generateNews() {
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                int titleCount = 1;
                int contentCount = 1;
    
                @Override
                public void run() {
                    send(new NewsModel("title:" + titleCount++, "content:" + contentCount++));
                }
            }, DELAY, 5000);
        }
    
        @Override
        public void register(MyObserver myObserver) {
            if (myObserver == null)
                return;
            synchronized (this) {
                if (!mObservers.contains(myObserver))
                    mObservers.add(myObserver);
            }
        }
    
        @Override
        public synchronized void remove(MyObserver myObserver) {
            mObservers.remove(myObserver);
        }
    
        @Override
        public void send(NewsModel model) {
            for (MyObserver observer : mObservers) {
                observer.receive(model);
            }
        }
    }
    
    1. 测试类
    /**
     * 测试类
     */
    public class Test {
        public static void main(String[] args) {
    
            NewsProvider provider = new NewsProvider();
            User user;
            for (int i = 0; i < 10; i++) {
                user = new User("user:"+i);
                provider.register(user);
            }
    
        }
    }
    

    运行测试类,就能看到每隔5秒,观察者收到了报纸。(其实就是观察者触发了某个receive方法)


    三、java自带的观察者api

    public interface Observer {
        void update(Observable o, Object arg);
    }
    
    public class Observable {
        private boolean changed = false;
        private Vector<Observer> obs;
    
        public Observable() {
            obs = new Vector<>();
        }
    
        public synchronized void addObserver(Observer o) {
            if (o == null)
                throw new NullPointerException();
            if (!obs.contains(o)) {
                obs.addElement(o);
            }
        }
    
        public synchronized void deleteObserver(Observer o) {
            obs.removeElement(o);
        }
    
        public void notifyObservers() {
            notifyObservers(null);
        }
    
        public void notifyObservers(Object arg) {
     
            Object[] arrLocal;
    
            synchronized (this) {
                if (!changed)
                    return;
                arrLocal = obs.toArray();
                clearChanged();
            }
    
            for (int i = arrLocal.length-1; i>=0; i--)
                ((Observer)arrLocal[i]).update(this, arg);
        }
    
        public synchronized void deleteObservers() {
            obs.removeAllElements();
        }
    
        protected synchronized void setChanged() {
            changed = true;
        }
    
        protected synchronized void clearChanged() {
            changed = false;
        }
    
    
        public synchronized boolean hasChanged() {
            return changed;
        }
    
        public synchronized int countObservers() {
            return obs.size();
        }
    }
    
    

    源码比较简单,这个类是从JDK1.0就开始出现,

    private Vector<Observer> obs;这句代码用来存放观察者对象的,可以看到使用的还是Vector类。

    Observable提供的changed属性

        private boolean changed = false;
    

    通过设置这个变量来确定是否通知观察者。

  • 相关阅读:
    一个很low的登录界面
    python 中的反射
    【Java】SpringMVC中URL传递参数-ant风格
    【springMVC】用maven构建第一个springMVC程序
    【Mybatis】mybatis登录实例
    【Mybatis】Mybatis简单使用
    【Java】Quartz的简单使用
    【Java】腾讯云发送短信验证码-Struts2
    【Java】web项目中发送邮件验证码-Struts2
    Bootstrap-fileinput文件上传组件
  • 原文地址:https://www.cnblogs.com/heliusKing/p/12228524.html
Copyright © 2011-2022 走看看