美文网首页
设计模式-观察者模式(行为型)

设计模式-观察者模式(行为型)

作者: NealLemon | 来源:发表于2019-08-24 11:12 被阅读0次

    定义

    • 定义了对象之间的一对多依赖,让多个观察者对象同时监听某个主题对象,当主题对象发生变化时,它的所有依赖者(观察者)都会受到通知并更新。
    • 比如我们的朋友圈,当某人发布一条动态后,只要你在动态下点赞或者评论后,其他好友对该条动态也点赞或评论时,你就可以收到提示,这就是一种观察者模式的体现。

    适用场景

    • 关联行为场景,建立一套触发机制。

    优点

    • 抽象耦合
    • 支持广播通信

    缺点

    • 避免循环依赖
    • 过多的细节,提高时间消耗和程序的复杂度

    代码

    由于JDK实现了观察者模式的接口,接下来我们来实现一下微博消息提醒这个效果。

    首先我们先来进行抽象

    我们操作的步骤是

    微博 -》 发布动态 -》其他人接收到动态并且点赞

    微博(WeiBo

    首先我们要明白,我们观察的是朋友圈,而不是某个动态,当朋友圈内状态有所变化时,通知其他人。

    /**
     * 微博 被观察对象
     */
    public class WeiBo extends Observable {
    
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        /**
         * 发布动态
         */
        public void publishDynamicState(WeiBo weiBo, DynamicState dynamicState) {
            System.out.println(weiBo.getName() +"发布了一条内容为:" + dynamicState.getContent()+"的动态");
            //改变状态 标识当前对象有所改变
            setChanged();
            //通知观察者
            notifyObservers();
        }
    }
    
    

    我们在这里主要用到父类Observable中的

    添加观察者(在测试类中会有体现)

    /**
     * Adds an observer to the set of observers for this object, provided
     * that it is not the same as some observer already in the set.
     * The order in which notifications will be delivered to multiple
     * observers is not specified. See the class comment.
     *
     * @param   o   an observer to be added.
     * @throws NullPointerException   if the parameter o is null.
     */
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }
    

    通知观察者

    /**
     * If this object has changed, as indicated by the
     * <code>hasChanged</code> method, then notify all of its observers
     * and then call the <code>clearChanged</code> method to indicate
     * that this object has no longer changed.
     * <p>
     * Each observer has its <code>update</code> method called with two
     * arguments: this observable object and the <code>arg</code> argument.
     *
     * @param   arg   any object.
     * @see     java.util.Observable#clearChanged()
     * @see     java.util.Observable#hasChanged()
     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
     */
    public void notifyObservers(Object arg) {
        /*
         * a temporary array buffer, used as a snapshot of the state of
         * current Observers.
         */
        Object[] arrLocal;
    
        synchronized (this) {
            /* We don't want the Observer doing callbacks into
             * arbitrary code while holding its own Monitor.
             * The code where we extract each Observable from
             * the Vector and store the state of the Observer
             * needs synchronization, but notifying observers
             * does not (should not).  The worst result of any
             * potential race-condition here is that:
             * 1) a newly-added Observer will miss a
             *   notification in progress
             * 2) a recently unregistered Observer will be
             *   wrongly notified when it doesn't care
             */
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }
    
        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }
    

    改变状态,允许通知

    /**
     * Marks this <tt>Observable</tt> object as having been changed; the
     * <tt>hasChanged</tt> method will now return <tt>true</tt>.
     */
    protected synchronized void setChanged() {
        changed = true;
    }
    

    以上三个方法是我们经常用到的。

    微博动态(DynamicState)

    /**
     * 微博动态
     */
    public class DynamicState {
        //微博动态内容
        private String content;
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
    }
    

    微博中的朋友(OtherFriends)

    /**
     * 其他朋友 观察者
     */
    public class OtherFriends implements Observer {
    
        //朋友名称
        private String name;
    
        public OtherFriends(String name) {
            this.name = name;
        }
    
        @Override
        public void update(Observable o, Object arg) {
            WeiBo circleOfFriends = (WeiBo) o;
            System.out.println("朋友;" + name + "在"+circleOfFriends.getName()+"的微博,发布的动态:下点赞了。");
        }
    }
    
    

    朋友作为观察者,在点赞后可以得到其他人的点在通知。

    UML

    observerUML.jpg

    我们清晰的看到 观察者和被观察者的依赖关系。

    测试

    public class ObserverTest {
    
        public static void main(String[] args) {
            /**
             * 李雷的微博
             */
            WeiBo weiBo = new WeiBo();
            weiBo.setName("Lilei");
            /**
             * 李雷的好友韩梅梅
             */
            OtherFriends otherFriends1 = new OtherFriends("HanMeimei");
            /**
             * 李雷的好友Bob
             */
            OtherFriends otherFriends2 = new OtherFriends("Bob");
            /**
             * 关注了李雷的微博
             */
            weiBo.addObserver(otherFriends1);
            weiBo.addObserver(otherFriends2);
            /**
             * 李雷发布新动态
             */
            DynamicState dynamicState = new DynamicState();
            dynamicState.setContent("How are you?");
            weiBo.publishDynamicState(weiBo,dynamicState);
        }
    }
    

    结果

    Lilei发布了一条内容为:How are you?的动态
    朋友;Bob在Lilei的微博,发布的动态:下点赞了。
    朋友;HanMeimei在Lilei的微博,发布的动态:下点赞了。
    

    其他开源

    Spring 事件

    事件监听接口ApplicationListener 相当于 java.util.Observer

    @FunctionalInterface
    public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    
       /**
        * Handle an application event.
        * @param event the event to respond to
        */
       void onApplicationEvent(E event);
    
    }
    

    事件发布接口 ApplicationEventPublisherAware 相当于 java.util.Observable

    /**
     * Interface to be implemented by any object that wishes to be notified
     * of the ApplicationEventPublisher (typically the ApplicationContext)
     * that it runs in.
     *
     * @author Juergen Hoeller
     * @author Chris Beams
     * @since 1.1.1
     * @see ApplicationContextAware
     */
    public interface ApplicationEventPublisherAware extends Aware {
    
       /**
        * Set the ApplicationEventPublisher that this object runs in.
        * <p>Invoked after population of normal bean properties but before an init
        * callback like InitializingBean's afterPropertiesSet or a custom init-method.
        * Invoked before ApplicationContextAware's setApplicationContext.
        * @param applicationEventPublisher event publisher to be used by this object
        */
       void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
    
    }
    

    当然 Spring中的具体实现比较复杂,这里只是给出了接口定义,感兴趣的小伙伴可以自己实现一个事件发布监听就理解其中的道理了。也可以参看一下之前我整合 Spring Cloud Bus中的实现

    Spring Cloud系列--Spring Cloud Bus(二)

    小结

    在观察者模式中,其实最难的就是抽象观察者和被观察者之间的联系,如果捋清楚这些,相信实现各种监听和通知推送都不成问题。

    相关文章

      网友评论

          本文标题:设计模式-观察者模式(行为型)

          本文链接:https://www.haomeiwen.com/subject/apbfectx.html