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

    设计模式-观察者模式

    定义

    观察者模式(Observer Pattern)又叫发布-订阅模式。定义一种一对多的依赖关系。
    一个主题对象可以被多个观察者对象同事监听,使得每当主题对象状态发生变化时,所有依赖于它的对象都会得到通知并被自动更新

    属于行为模式。

    适用场景

    1. 当一个抽象模型包含2个方面内容,其中一个方面依赖于另一个方面;
    2. 其他一个或多个对象的变化依赖于另一个对象的变化;
    3. 实现类似广播机制的功能,无需知道具体收听者,只需分化
    4. 多层级嵌套,形成一种链式触发机制,使得事件具备跨域通知

    代码示例

    手写观察者模式

    拿鼠标举例

    1. 创建事件类
    package com.black.design.pattern.observer.mouse;
    
    import java.lang.reflect.Method;
    
    // 事件类
    public class Event {
        // 事件名称
        private String name;
        // 事件源
        private Object source;
        // 事件触发,通知目标(观察者)
        private Object target;
        // 观察者回调函数
        private Method callback;
        // 创建事件的时间
        private String createTime;
        
        public Event(String name) {
            this.name = name;
        }
        
        public Event(Object target, Method callback) {
            this.target = target;
            this.callback = callback;
        }
    
        public String getName() {
            return name;
        }
    
        public Object getSource() {
            return source;
        }
    
        public Object getTarget() {
            return target;
        }
    
        public Method getCallback() {
            return callback;
        }
    
        public String getCreateTime() {
            return createTime;
        }
    
        public Event setName(String name) {
            this.name = name;
            return this;
        }
    
        public Event setSource(Object source) {
            this.source = source;
            return this;
        }
    
        public Event setTarget(Object target) {
            this.target = target;
            return this;
        }
    
        public Event setCallback(Method callback) {
            this.callback = callback;
            return this;
        }
    
        public Event setCreateTime(String createTime) {
            this.createTime = createTime;
            return this;
        }
    }
    
    
    1. 创建事件监听类,当事件触发时,默认调用 回调类对应的on方法
    package com.black.design.pattern.observer.mouse;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Map;
    
    // 被观察者的抽象
    public class EventListener {
    
        // 事件
        protected Map<String, Event> events = new HashMap<String, Event>();
        // 感兴趣的事件
        public void interestEvent(String eventType, Object target, Method callback) {
            events.put(eventType, new Event(target, callback));
        }
        // 感兴趣的事件
        public void interestEvent(String eventType, Object target) throws NoSuchMethodException, SecurityException {
            // 回调方法 
            Method callback = target.getClass().getMethod("on" + toUpperFirstChar(eventType), Event.class);
            interestEvent(eventType, target, callback);
        }
        
        // 首字母转为大写
        private String toUpperFirstChar(String eventType) {
           char [] chars = eventType.toCharArray();
           chars[0] -=32;
           return new String(chars);
        }
        
        // 触发事件
        protected void triger(String triger) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
            if (!events.containsKey(triger)) {return;}
            Event t = events.get(triger);
            t.setSource(this);
            t.setCreateTime(String.valueOf(System.nanoTime()));
            
            if(t.getCallback() != null) {
                t.getCallback().invoke(t.getTarget(), t);
            }
             }
    }
    
    
    1. 创建鼠标事件类型
    
    package com.black.design.pattern.observer.mouse;
    
    // 事件类型
    public class MouseEventType {
        // 单击事件
        public static final String ON_CLICK="click";
     // 双击事件
        public static final String ON_DOUBLE_CLICK="doubleClick";
     // 移动事件
        public static final String ON_MOVE="move";
     // 滑动事件
        public static final String ON_SCROLL="scroll";
    }
    
    
    1. 创建鼠标类
    package com.black.design.pattern.observer.mouse;
    
    import java.lang.reflect.InvocationTargetException;
    
    // 鼠标
    public class Mouse{
        // 鼠标监听器
        private MouseEventListener listener;
        
        // 注册监听器
        public void registerListener(MouseEventListener listener) {
            this.listener = listener;
        }
        
        // 单击
        public void click() {
            System.out.println("单击鼠标");
            triger(MouseEventType.ON_CLICK);
        }
     // 双击
        public void doubleClick() {
            System.out.println("双击鼠标");
            triger(MouseEventType.ON_DOUBLE_CLICK);
        }
     // 移动
        public void move() {
            System.out.println("鼠标移动");
            triger(MouseEventType.ON_MOVE);
        }
        
       // scroll
        public void scroll() {
            System.out.println("鼠标滑动");
            triger(MouseEventType.ON_SCROLL);
         }
        
        // 触发监听器
        private void triger(String eventType) {
            if(listener != null) {
                try {
                    listener.triger(eventType);
                } catch (Exception e) {
                    e.printStackTrace();
                    return;
                }
            }
        }
    }
    
    
    1. 创建回调类
    package com.black.design.pattern.observer.mouse;
    // 回调类
    public class MouseCallBack {
    
    	// 点击回调
        public void onClick(Event t) {
            System.out.println("回调 on click");
        }
        // 双击回调
        public void onDoubleClick(Event t) {
    		
    		
            System.out.println("回调 on double click");
        }
    }
    
    
    1. 测试
    package com.black.design.pattern.observer.mouse;
    
    import java.awt.event.MouseListener;
    
    // 测试类
    public class MouseTest {
    
        public static void main(String[] args) throws NoSuchMethodException, SecurityException {
            
            // 实例化鼠标
            Mouse mouse = new Mouse();
            
            // 回调类
            MouseCallBack callBack = new MouseCallBack();
           // 实例化鼠标事件监听器
            MouseEventListener listener = new MouseEventListener();
            // 感兴趣的事件是 单击,如果鼠标单击则会回调 callBack 类
            listener.interestEvent(MouseEventType.ON_CLICK, callBack);
            
            // 鼠标注册监听器,监听器监听鼠标的行为
            mouse.registerListener(listener);
            
            // 单击鼠标
            System.out.println("======单击鼠标======");
            mouse.click();
          
          // 双击鼠标
            System.out.println("======双击鼠标======");
            mouse.doubleClick();
            
        }
    }
    
    

    运行结果:

    ======单击鼠标======
    单击鼠标
    监听到来自com.black.design.pattern.observer.mouse.MouseEventListener的click事件
    事件回调onClick方法
    ======双击鼠标======
    双击鼠标
    
    

    JDK 提供的观察者模式

    1. 创建一个 Observer 接口的实现类
    package com.black.design.pattern.observer.jdk;
    
    import java.util.Observable;
    import java.util.Observer;
    
    /**
     * 观察者
     * @author black
     *
     */
    public class MyObserver implements Observer{
    	
    	private String name;
    
    	public MyObserver(String name) {
    		this.name = name;
    	}
    
    	@Override
    	public void update(Observable o, Object arg) {
    		Target target = (Target)o;
    		System.out.println(name + " 接收到信息: " + arg);
    	}
    }
    
    
    1. 创建 Observable 类的子类
    package com.black.design.pattern.observer.jdk;
    
    import java.util.Observable;
    import java.util.Observer;
    
    /**
     * 被观察者
     * @author black
     *
     */
    public class Target extends Observable {
    
    	@Override
    	public synchronized void addObserver(Observer o) {
    		super.addObserver(o);
    	}
    	
    	public void postNotice(String notice) {
    		System.out.println("发布消息: " + notice);
    		setChanged();
    		notifyObservers(notice);
    	}
    }
    
    1. 测试类
    package com.black.design.pattern.observer.jdk;
    
    /**
     * 观察者测试类
     * @author black
     *
     */
    public class ObserverTest {
    
    	public static void main(String[] args) {
    		// 创建被观察者 target
    		Target target = new Target();
    		// 创建2个观察者 blackMyObserver 和 xiaomingMyObserver
    		MyObserver blackMyObserver = new MyObserver("black");
    		MyObserver xiaomingMyObserver = new MyObserver("xiaoming");
    		target.addObserver(blackMyObserver);
    		target.addObserver(xiaomingMyObserver);
    		// 被观察者 target 发出一个通知
    		System.out.println("=======第1条通知=========");
    		target.postNotice("明天下午8点停电!");
    		System.out.println("=======第2条通知=========");
    		target.postNotice("后天早上8点点打卡!");
    	}
    }
    

    测试结果:

    =======第1条通知=========
    发布消息: 明天下午8点停电!
    xiaoming 接收到信息: 明天下午8点停电!
    black 接收到信息: 明天下午8点停电!
    =======第2条通知=========
    发布消息: 后天早上8点点打卡!
    xiaoming 接收到信息: 后天早上8点点打卡!
    black 接收到信息: 后天早上8点点打卡!
    

    Guava 提供的观察者模式

    1. 引入 guava jar 包
       <dependency>
    		<groupId>com.google.guava</groupId>
    		<artifactId>guava</artifactId>
    		<version>20.0</version>
    	</dependency>
    
    1. 创建 事件类
    package com.black.design.pattern.observer.guava;
    
    import com.google.common.eventbus.Subscribe;
    
    /**
     * 使用@Subscribe注解,订阅观察的方法
     * @author black
     *
     */
    public class GuavaEvent {
    
    	@Subscribe
    	public void subscribe(String str) {
    		//执行业务逻辑
    		System.out.println("调用 subscribe,传入参数:" + str);
    	}
    }
    
    
    1. 创建测试类
    
    package com.black.design.pattern.observer.guava;
    
    import com.google.common.eventbus.EventBus;
    
    public class GuavaEventTest {
    
    	public static void main(String[] args) {
    		// 创建事件总线
    		EventBus eventBus = new EventBus();
    		// 创建自定义的事件
    		GuavaEvent guavaEvent = new GuavaEvent();
    		// 将自定义的事件注册到 EventBus 中
    		eventBus.register(guavaEvent);
    		// EventBus 发送消息,各个事件会接受到这个消息
    		eventBus.post("black");
    	}
    }
    
    

    测试结果:

    调用 subscribe,传入参数:black
    
  • 相关阅读:
    php性能测试工具
    linux的openssl
    Nginx与Apache的Rewrite规则的区别
    mysql索引总结----mysql 索引类型以及创建
    不支持正在使用的 .Net 组帧模式。有关详细信息,请参阅服务器日志--解决方案
    c#获取网页源代码
    关于线程间操作无效: 从不是创建控件“xx”的线程访问它,错误解决方法(自定义委托和系统委托Action或Func解决)
    联想笔记本官网驱动下载
    easy ui combotree的操作
    c# 搜狗拼音输入法,刷输入速度和累计输入
  • 原文地址:https://www.cnblogs.com/lihw-study/p/15227053.html
Copyright © 2011-2022 走看看