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

      一、Observer模式定义对象间的一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。JDK里提供的observer设计模式的实现由java.util.Observable类和 java.util.Observer接口组成。从名字上可以清楚的看出两者在Observer 设计模式中分别扮演的角色:Observer是观察者角色,Observable是被观察目标(subject)角色。

      二、观察者模式的优点:

        1、 Subject和Observer之间是松耦合的,分别可以各自独立改变。
        2、 Subject在发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知。
        3、 遵守大部分GRASP原则和常用设计原则,高内聚、低耦合。
      三、观察者模式的缺陷:
        1、 松耦合导致代码关系不明显,有时可能难以理解。(废话)
        2、 如果一个Subject被大量Observer订阅的话,在广播通知的时候可能会有效率问题。(毕竟只是简单的遍历)
      四、结构图
        1)注册时:
        

        2)Subject触发时:

        

      五、这里写了一个实际开发中很有用的观察者模式的架构

      1)观察者实现,抽象类的目的在于开发者只需要处理onMessage中的数据即可,不需要处理更多数据

    package com.pinnet.observer;
    
    import com.pinnet.observable.MessageObservable;
    
    import javax.jms.ObjectMessage;
    import java.util.Observable;
    import java.util.Observer;
    
    /**
     * 观察者
     * 抽象类的目的是更好的简化开发,实际开发中很有必要
     */
    public abstract class MessageObserver implements Observer {
    
        /**
         * 目的是在操作观察者的时候就加入到对应的被观察者中
         * @param messageObservable
         */
        public MessageObserver(MessageObservable messageObservable) {
            if (messageObservable == null) {
                return;
            }
            messageObservable.addObserver(this);
        }
    
        /**
         * 数据存在改变时触发,也是消息接收者
         * @param observable
         * @param object
         */
        public void update(Observable observable, Object object) {
            //这里采用ObjectMessage的数据形式,为了更好的传输对象数据
            ObjectMessage objectMessage = (ObjectMessage) object;
            onMessage(objectMessage);
        }
    
        /**
         * 消息处理,需要具体实现
         * @param objectMessage
         */
        public abstract void onMessage(ObjectMessage objectMessage);

    }

      2)被观察者的继承,被观察者的方法基本都完善了,我们这里继承的目的是为了更好的理解

    package com.pinnet.observable;
    
    import javax.jms.ObjectMessage;
    import java.util.Observable;
    
    /**
     * 被观察者
     * 用来发送消息,这里不直接应用,采用消息中心模式在处理
     */
    public class MessageObservable extends Observable {
    
        /**
         * 发送消息在center中使用
         * @param objectMessage
         */
        public void sendMessage(ObjectMessage objectMessage) {
            //设置改变点
            setChanged();
            //发给观察者
            notifyObservers(objectMessage);
        }
    }

      3)消息处理中心,目的是为了提供更有用的工具

    package com.pinnet.center;
    
    import com.pinnet.observable.MessageObservable;
    import org.apache.activemq.command.ActiveMQObjectMessage;
    
    import javax.jms.JMSException;
    import javax.jms.ObjectMessage;
    import java.io.Serializable;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * 消息处理中心,所有操作全部在这里
     */
    public class MessageCenter {
    
        //用于保存具体被观察者,发送数据,注册等
        public static Map<MessageType, MessageObservable> messageMap = new ConcurrentHashMap<MessageType, MessageObservable>();
    
        /**
         * 获取被观察者,添加观察者
         * @param messageType
         * @return
         */
        public MessageObservable getMessageObservable(MessageType messageType) {
            if (messageMap.containsKey(messageType)) {
                return messageMap.get(messageType);
            } else {
                MessageObservable messageObservable = new MessageObservable();
                messageMap.put(messageType, messageObservable);
                return messageObservable;
            }
        }
    
        /**
         * 发送消息,统一入口
         * @param messageType
         * @param serializable
         */
        public void sendMessage(MessageType messageType, Serializable serializable) {
            if (messageMap.containsKey(messageType)) {
                try {
                    MessageObservable messageObservable = messageMap.get(messageType);
                    //这里采用的是ActiveMQ中实现类,当然可以自己实现ObjectMessage也可以
                    ObjectMessage objectMessage = new ActiveMQObjectMessage();
                    objectMessage.setObject(serializable);
                    //被观察者发送给每个观察者
                    messageObservable.sendMessage(objectMessage);
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 枚举类的目的是更好的控制数据发送
         */
        public enum MessageType {
            PUB,SUB
        }
    }

      4)测试:简单实现一下即可,当然需要注册(注册部分可以写成xml,也可以自己写启动类)

      a、写了两个观察者的实现类

    package com.pinnet.observer.impl;
    
    import com.pinnet.observable.MessageObservable;
    import com.pinnet.observer.MessageObserver;
    
    import javax.jms.JMSException;
    import javax.jms.ObjectMessage;
    
    /**
     * 消息监听
     */
    public class PUBMessageListener extends MessageObserver {
    
        /**
         * 目的是在操作观察者的时候就加入到对应的被观察者中
         *
         * @param messageObservable
         */
        public PUBMessageListener(MessageObservable messageObservable) {
            super(messageObservable);
        }
    
        /**
         * 消息处理
         * @param objectMessage
         */
        public void onMessage(ObjectMessage objectMessage) {
            try {
                System.out.println(objectMessage.getObject());
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    
    }
    package com.pinnet.observer.impl;
    
    import com.pinnet.observable.MessageObservable;
    import com.pinnet.observer.MessageObserver;
    
    import javax.jms.JMSException;
    import javax.jms.ObjectMessage;
    
    public class SUBMessageListener extends MessageObserver {
    
        /**
         * 目的是在操作观察者的时候就加入到对应的被观察者中
         *
         * @param messageObservable
         */
        public SUBMessageListener(MessageObservable messageObservable) {
            super(messageObservable);
        }
    
        /**
         * 消息处理
         * @param objectMessage
         */
        public void onMessage(ObjectMessage objectMessage) {
            try {
                System.out.println(objectMessage.getObject());
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    
    }

      b、注册:统一写在了MessageCenter中

    /**
         * 注册
         */
        public static void init() {
            new PUBMessageListener(MessageCenter.getMessageObservable(MessageType.PUB));
            new PUBMessageListener(MessageCenter.getMessageObservable(MessageType.PUB));
            new SUBMessageListener(MessageCenter.getMessageObservable(MessageType.SUB));
        }

      c、测试:

    package com.pinnet;
    
    import com.pinnet.center.MessageCenter;
    
    public class Test {
    
        public static void main(String[] args) {
            MessageCenter.init();
            MessageCenter.sendMessage(MessageCenter.MessageType.PUB, "pub");
            MessageCenter.sendMessage(MessageCenter.MessageType.SUB, "sub");
        }
    }

      d、结果

      

      六、观察者模式应用还是很不错的,特别是在分发数据,socket推送过后的数据分发处理等。当然不会离开消息队列,下一个博客将写到jms的用法。

      七、源码参考:https://pan.baidu.com/s/1qBSIRXXRoMXsmHsi-yKehA

  • 相关阅读:
    转载 初学者必看——最简单最清晰的Struts2项目搭建流程
    五种常见设计模式
    第二则java读取excel文件代码
    使用Maven运行Java main的3种方式使用Maven运行Java main的3种方式
    C++模式学习------策略模式
    C++模式学习------工厂模式
    人生辣么多的谎言,没必要一个个试一下
    常用函数说明
    python 查看与更换工作目录
    unix常用命令记录
  • 原文地址:https://www.cnblogs.com/ll409546297/p/9169443.html
Copyright © 2011-2022 走看看