博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
观察者模式以及tomcat实现的观察者模式
阅读量:6307 次
发布时间:2019-06-22

本文共 8344 字,大约阅读时间需要 27 分钟。

hot3.png

观察者设计模式

观察者模式也称作发布订阅模式,监听器模式,被观察管理各个观察者,当被观察者的状态有变更的时候,会主动通知观察者。

         通常的情况下,我们会怎么实现如果一个对象的状态变更,通知到对相应状态感兴趣的类呢,这个可以分为主动通知和被动通知。

         主动通知:当实体的状态有变更,然后主动的通知到观察者我的状态变更了,观察者根据相应的状态实现自己的操作。

         被动通知:实体状态变更,不主动通知,然后观察者定时的去扫描目标状态,这种操作比较耗费资源,并且不能做到实时,所以一般都不采用这种方式。

模式结构

具体观察者模式是如何实现的呢?

首先会有一个目标对象Target,这个是被观察者主体,它持有一个观察者列表,观察者均会实现观察者接口中的通知方法,以便接收通知。当观察者状态有变更时,会循环持有的观察者列表,然后调用其通知方法。

123417_ZvGB_2457218.png

现在我们模拟一个场景,来用观察者模式来实现,场景是家里面有一套智能家庭影院,当我们打开观影模式时,此时家里窗帘自动关闭,屋内的灯光自动调整为昏暗色,然后音响调整为环绕声。当家庭影院从观影模式调到正常模式时,窗帘拉开,屋内灯光打开,音响调整到立体声。

实现

手工实现

首先我们有一个家庭影院的主体,然后有一些周边的设备,智能窗帘,智能音响和灯光。代码实现如下:

package design.observer;/** * Created by wangtengfei1 on 2017/9/13. * 家庭影院的模式,分别是放映模式和正常模式,实际上也就是事件 */public enum EventMode {    VIDEO,NORMAL}
package design.observer;import java.util.ArrayList;import java.util.List;/** * Created by wangtengfei1 on 2017/9/13. * 家庭影院主体 */public class HomeVideo {    EventMode eventMode;//观影模式    //注册的观察者列表    List
observerLists = new ArrayList
(); //增加观察者 public void addObserver(HomeVideoObserver observer){ observerLists.add(observer); } //删除观察者 public void deleteObserver(HomeVideoObserver observer){ observerLists.remove(observer); } //通知观察者 public void notifyObserver(EventMode eventMode){ for(HomeVideoObserver observer:observerLists){ observer.update(this.eventMode); } } //家庭影院开关 public void turn(EventMode eventMode){ this.eventMode = eventMode; notifyObserver(eventMode); }}
package design.observer;/** * Created by wangtengfei1 on 2017/9/13. */public interface HomeVideoObserver {    public void update(EventMode eventMode);}package design.observer;/** * Created by wangtengfei1 on 2017/9/13. * 智能音响 */public class Audio implements HomeVideoObserver {    @Override    public void update(EventMode eventMode) {        if(eventMode==EventMode.NORMAL){            System.out.println("\t>>>立体声模式播放");        }        if (eventMode ==EventMode.VIDEO){            System.out.println("\t>>>环绕声模式播放");        }    }}package design.observer;/** * Created by wangtengfei1 on 2017/9/13. * 智能灯泡 */public class Bulb implements HomeVideoObserver {    @Override    public void update(EventMode eventMode) {        if(eventMode==EventMode.NORMAL){            System.out.println("\t>>>灯光调亮");        }        if (eventMode ==EventMode.VIDEO){            System.out.println("\t>>>灯光调暗");        }    }}package design.observer;/** * Created by wangtengfei1 on 2017/9/13. * 智能窗帘 */public class WindowCurtains implements HomeVideoObserver {    @Override    public void update(EventMode eventMode) {        if(eventMode==EventMode.NORMAL){            System.out.println("\t>>>窗帘开启");        }        if (eventMode ==EventMode.VIDEO){            System.out.println("\t>>>窗帘关闭");        }    }}

遥控器,也就是客户端

package design.observer;/** * Created by wangtengfei1 on 2017/9/13. * 遥控器 */public class RemoteControl {    private static final HomeVideo homeVideo = new HomeVideo();    public static void main(String[] args) throws Exception {        HomeVideoObserver bulb = new Bulb();        HomeVideoObserver windowCurtains = new WindowCurtains();        HomeVideoObserver audio = new Audio();        homeVideo.addObserver(bulb);        homeVideo.addObserver(windowCurtains);        homeVideo.addObserver(audio);        System.out.println(">>遥控器按下播放按钮");        homeVideo.turn(EventMode.VIDEO);        Thread.sleep(100);        System.out.println(">>100后影片播放完毕");        homeVideo.turn(EventMode.NORMAL);    }}

输出如下

123656_2jXq_2457218.png

JDK实现

由于观察者模式太常用了,所以jdk在工具类中实现了一个观察者,只需要我们实现Observer接口,并且实现其update方法即可。现在用jdk自带的观察者模式改造一下下面的程序。

package design.jdkObserver;import design.observer.EventMode;import design.observer.HomeVideoObserver;import java.util.ArrayList;import java.util.List;import java.util.Observable;import java.util.Observer;/** * Created by wangtengfei1 on 2017/9/13. */public class HomeVideo extends Observable {    public EventMode eventMode;//观影模式    //家庭影院开关    public void turn(EventMode eventMode){        this.eventMode = eventMode;        this.setChanged();        super.notifyObservers();    }}
package design.jdkObserver;import design.observer.EventMode;import java.util.Observable;import java.util.Observer;/** * Created by wangtengfei1 on 2017/9/13. * 智能音响 */public class Audio implements Observer {    public Audio() {    }    public Audio(Observable observable) {        observable.addObserver(this);    }    @Override    public void update(Observable o, Object arg) {        if (o instanceof HomeVideo) {            HomeVideo video = (HomeVideo) o;            if (video.eventMode == EventMode.NORMAL) {                System.out.println("\t>>>立体声模式播放");            }            if (video.eventMode == EventMode.VIDEO) {                System.out.println("\t>>>环绕声模式播放");            }        }    }}package design.jdkObserver;import design.observer.EventMode;import design.observer.HomeVideoObserver;import java.util.Observable;import java.util.Observer;/** * Created by wangtengfei1 on 2017/9/13. * 智能灯泡 */public class Bulb implements Observer {    public Bulb(){}    public Bulb(Observable observable){        observable.addObserver(this);    }    @Override    public void update(Observable o, Object arg) {        if (o instanceof HomeVideo) {            HomeVideo video = (HomeVideo) o;            if(video.eventMode==EventMode.NORMAL){                System.out.println("\t>>>灯光调亮");            }            if (video.eventMode ==EventMode.VIDEO){                System.out.println("\t>>>灯光调暗");            }        }    }}package design.jdkObserver;import design.observer.EventMode;import design.observer.HomeVideoObserver;import java.util.Observable;import java.util.Observer;/** * Created by wangtengfei1 on 2017/9/13. * 智能窗帘 */public class WindowCurtains implements Observer {    public WindowCurtains(){}    public WindowCurtains(Observable observable){        observable.addObserver(this);    }    @Override    public void update(Observable o, Object arg) {        if (o instanceof HomeVideo) {            HomeVideo video = (HomeVideo) o;            if(video.eventMode==EventMode.NORMAL){                System.out.println("\t>>>窗帘开启");            }            if (video.eventMode ==EventMode.VIDEO){                System.out.println("\t>>>窗帘关闭");            }        }    }}

jdk方式的观察者模式的遥控器,客户端

package design.jdkObserver;import design.observer.EventMode;import java.util.Observer;/** * Created by wangtengfei1 on 2017/9/13. */public class JdkRemoteControl {    public static void main(String[] args) throws Exception {        HomeVideo homeVideo = new HomeVideo();        Observer audio = new Audio(homeVideo);        Observer bulb = new Bulb(homeVideo);        Observer windowCurtains = new WindowCurtains(homeVideo);        //或者采用下面的这种方式,是等效的        /**         *  Observer audio = new Audio();         *  homeVideo.addObserver(audio);         */        System.out.println(">>遥控器按下播放按钮");        homeVideo.turn(EventMode.VIDEO);        Thread.sleep(100);        System.out.println(">>100后影片播放完毕");        homeVideo.turn(EventMode.NORMAL);    }}

输出结果和上面以后,就不在贴出了,可以看出,jdk实现的更简洁,并且安全性也更高。

tomcat实现

tomcat在监听容器声明周期事件的时候也采用了观察者模式,但是tomcat并没有采用jdk实现的观察者模式,而是自己实现了一套观察者模式,因为它需要不同的监听器,包括对声明周期的监听,对容器的监听,这样能更加契合它本身的业务。看一下tomcat是怎么实现的。

首先观察对象要实现LifecycleListener接口的LifecycleEvent方法。这个方法接收一个LifecycleEvent对象,来标明此时发生了什么事儿。

而监听对象则是LifecycleBase类,这个类提供了addLifecycleListener、findLifecycleListeners、removeLifecycleListener、fireLifecycleEvent这些方法,分别是增加监听器,查找监听器,移除监听器和通知各个监听器这些方法。调用通知的方法在什么地方呢,就是在于容器状态改变时,例如Server启动时,在StandardServer在调用start方法启动,然后方法内调到startInternal方法中,会传递一个Configure_start事件,然后调用fireLifecycleEvent通知到各个监听者

public interface LifecycleListener {    /**     * Acknowledge the occurrence of the specified event.     *     * @param event LifecycleEvent that has occurred     */    public void lifecycleEvent(LifecycleEvent event);}

123846_O194_2457218.png

org.apache.catalina.core. StandardServer监听器通知方式 fireLifecycleEvent

@Override    protected void startInternal() throws LifecycleException {        fireLifecycleEvent(CONFIGURE_START_EVENT, null);        setState(LifecycleState.STARTING);        globalNamingResources.start();        // Start our defined Services        synchronized (servicesLock) {            for (int i = 0; i < services.length; i++) {                services[i].start();            }        }    }

 

转载于:https://my.oschina.net/u/2457218/blog/1536680

你可能感兴趣的文章
Linux下修改Mysql的用户root的密码
查看>>
我的友情链接
查看>>
[转载] 唐浩明评点曾国藩家书(上)——封面序言及目录
查看>>
mysql 密码重置
查看>>
oschina openapi php 调用
查看>>
MySQL MVCC && 事务隔离级别 && 锁
查看>>
[转载] 七龙珠第一部——第014话 竞争者来访
查看>>
手把手系列:(三)安装Oracle 12c数据库- linux
查看>>
WebView控件中的onConsoleMessage方法不被调用
查看>>
MyBatis学习总结(9)——使用MyBatis Generator自动创建代码
查看>>
MyBatis学习总结(八)——Mybatis3.x与Spring4.x整合
查看>>
了解SQL中 inner join、 left join 、right join、 outer join之间的区别
查看>>
app刚开始启动时(即:appdelegate文件中)可以写的几个功能
查看>>
MyBatis学习总结(1)——MyBatis快速入门
查看>>
Spring常用注解
查看>>
squid缓存代理服务基本配置
查看>>
Spring学习详解(1)——Spring入门详解
查看>>
自动安装linux系统(kickstart,pxe,tftp,dhcp,ftp)一
查看>>
ios系统相册中视频的获取和另存
查看>>
最近几天玩lxc的经历
查看>>