观察者设计模式java
观察者模式也称做发布订阅模式,监听器模式,被观察管理各个观察者,当被观察者的状态有变动的时候,会主动通知观察者。apache
一般的状况下,咱们会怎么实现若是一个对象的状态变动,通知到对相应状态感兴趣的类呢,这个能够分为主动通知和被动通知。设计模式
主动通知:当实体的状态有变动,而后主动的通知到观察者个人状态变动了,观察者根据相应的状态实现本身的操做。tomcat
被动通知:实体状态变动,不主动通知,而后观察者定时的去扫描目标状态,这种操做比较耗费资源,而且不能作到实时,因此通常都不采用这种方式。安全
具体观察者模式是如何实现的呢?ide
首先会有一个目标对象Target,这个是被观察者主体,它持有一个观察者列表,观察者均会实现观察者接口中的通知方法,以便接收通知。当观察者状态有变动时,会循环持有的观察者列表,而后调用其通知方法。工具
如今咱们模拟一个场景,来用观察者模式来实现,场景是家里面有一套智能家庭影院,当咱们打开观影模式时,此时家里窗帘自动关闭,屋内的灯光自动调整为昏暗色,而后音响调整为环绕声。当家庭影院从观影模式调到正常模式时,窗帘拉开,屋内灯光打开,音响调整到立体声。this
首先咱们有一个家庭影院的主体,而后有一些周边的设备,智能窗帘,智能音响和灯光。代码实现以下:spa
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在工具类中实现了一个观察者,只须要咱们实现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并无采用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(); } } }