观察者模式以及tomcat实现的观察者模式

原文:https://my.oschina.net/u/2457218/blog/1536680

观察者设计模式

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

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

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

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

模式结构

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

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

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

实现

手工实现

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

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<HomeVideoObserver> observerLists = new ArrayList<HomeVideoObserver>();

    //增加观察者
    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);
    }
}

输出如下

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);


}

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();
            }
        }
    }

 

Tomcat中对于观察者模式的一个经典使用就是用来控制组件生命周期的Lifecycle

首先我们将Lifecycle用到的几个类对应到Observer模式中的角色中去:

  • LifecycleListener: 对应抽象的Observer
  • ServerLifecycleLisener等: 对应具体的Observer
  • Lifecycle: 对应抽象的Subject
  • StandardServer等: 对应具体的Subject

除此之外还有两个辅助类:

  • LifecycleEvent: 可以定义事件类别,对不同的事件可区分处理,更加灵活
  • LifecycleSupport: 代理了Subject对于Observers的管理,将这个管理抽出来统一实现,以后如果修改只要修改LifecycleSupport类就可以了,不需要去修改所有的Subject,因为所有具体的Subject对Observers的操作都被代理给了LifecycleSupport类了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值