事件驱动模型-观察者模式实现案例
在上一篇中我们讨论了事件驱动模型的实现方式,其中用观察者模式实现的方式又有同步驱动、异步驱动两种,本片将给出这两种实现的案例。
同步驱动事件
1 定义接口
public interface Event {
}
public interface EventListener {
void notifyEvent(Event e);
}
public interface EventSource {
void addListener(EventListener e);
void removeListener(EventListener e);
}
2 定义数据元
public class WeatherData {
private int temperature = 0;
private int humidity = 0;
private int pressure = 0;
public WeatherData() {
}
public WeatherData(int temperary, int humidity, int pressure) {
this.temperature = temperary;
this.humidity = humidity;
this.pressure = pressure;
}
public boolean equals(int temperature, int humidity, int pressure) {
return (this.temperature == temperature) && (this.humidity == humidity) && (this.pressure == pressure);
}
public int getTemperature() {
return temperature;
}
public int getHumiDity() {
return humidity;
}
public int getPressure() {
return pressure;
}
public int getTemperatureVar(int temperature) {
return temperature - this.temperature;
}
public int getHumidityVar(int humidity) {
return humidity - this.humidity;
}
public int getPressureVar(int pressure) {
return pressure - this.pressure;
}
public void update(int temperary, int humidity, int pressure) {
this.temperature = temperary;
this.humidity = humidity;
this.pressure = pressure;
}
}
3 实现Event
public class WeatherDataChangeEvent implements Event{
private final int temperatureVar;
private final int humidityVar;
private final int pressureVar;
public WeatherDataChangeEvent(int tempVar, int humVar, int pressVar) {
this.temperatureVar = tempVar;
this.humidityVar = humVar;
this.pressureVar = pressVar;
}
public int getTemperatureVar() {
return temperatureVar;
}
public int getHuminityVar() {
return humidityVar;
}
public int getPressureVar() {
return pressureVar;
}
}
4 实现EventListener
public class TemperatureListener implements EventListener {
private int temperatrue = 0;
@Override
public void notifyEvent(Event e) {
int temperatrueVar = ((WeatherDataChangeEvent)e).getTemperatureVar();
temperatrue += temperatrueVar;
System.out.printf(" |- temperatrue[diff=%d] = %d\n", temperatrueVar, temperatrue);
}
}
public class HumidityListener implements EventListener {
private int humidity = 0;
@Override
public void notifyEvent(Event e) {
int humidityVar = ((WeatherDataChangeEvent)e).getHuminityVar();
humidity += humidityVar;
System.out.printf(" |- humidity[diff=%d] = %d\n", humidityVar, humidity);
}
}
public class PressureListener implements EventListener {
private int pressure = 0;
@Override
public void notifyEvent(Event e) {
int pressureVar = ((WeatherDataChangeEvent)e).getPressureVar();
pressure += pressureVar;
System.out.printf(" |- pressure[diff=%d] = %d\n", pressureVar, pressure);
}
}
5 实现EventSource
public class WeatherStation implements EventSource {
List<EventListener> listeners = new LinkedList<EventListener>();
WeatherData data = new WeatherData();
@Override
public void addListener(EventListener listener) {
listeners.add(listener);
}
@Override
public void removeListener(EventListener e) {
listeners.remove(e);
}
public void monitor() {
System.out.println("\n*************** Weather Station is Working... *******************");
System.out.println("Enter \"exit\" to Exit");
System.out.println("Enter \"[temperature] [humidity] [pressure]\" to Fill Weather Datas");
System.out.println("*******************************************************************\n");
monitor(new Scanner(System.in));
}
private void monitor(Scanner sc) {
while(true) {
if(sc.hasNext("exit"))
{
System.out.println("Weather Station exited!!!");
System.exit(0);
}
updateMeasurement(sc.nextInt(), sc.nextInt(), sc.nextInt());
sc.nextLine();
}
}
private void updateMeasurement(int temperature, int humidity, int pressure) {
if(!data.equals(temperature, humidity, pressure)) {
Event e = getEvent(data.getTemperatureVar(temperature), data.getHumidityVar(humidity), data.getPressureVar(pressure));
data.update(temperature, humidity, pressure);
dispatch(e);
}
}
private Event getEvent(int temperatureVar, int humidityVar, int pressureVar) {
return new WeatherDataChangeEvent(temperatureVar, humidityVar, pressureVar);
}
private void dispatch(Event e) {
for(EventListener listener : listeners) {
listener.notifyEvent(e);
}
}
}
异步驱动事件
异步驱动的代码与同步驱动的代码只有EventSource类的实现有区别,其余部分与同步驱动的代码一致。
1 定义接口
参考同步驱动代码。
2 定义数据元
参考同步驱动代码。
3 实现Event
参考同步驱动代码。
4 实现EventListener
参考同步驱动代码。
5 实现EventSource
public class WeatherStation implements EventSource{
List<EventListener> listeners = new LinkedList<EventListener>();
List<Event> events =new LinkedList<Event>();
WeatherData data = new WeatherData();
@Override
public void addListener(EventListener listener) {
listeners.add(listener);
}
@Override
public void removeListener(EventListener listener) {
listeners.remove(listener);
}
public void monitor() {
System.out.println("\n*************** Weather Station is Working... *******************");
System.out.println("Enter \"exit\" to Exit");
System.out.println("Enter \"[temperature] [humidity] [pressure]\" to Fill Weather Datas");
System.out.println("*******************************************************************\n");
Scanner sc = new Scanner(System.in);
new Thread(new Runnable() {
@Override
public void run() {
monitor(sc);
}}).start();;
new Thread(new Runnable() {
@Override
public void run() {
dispatch();
}}).start();;
}
private void monitor(Scanner sc) {
while(true) {
if(sc.hasNext("exit"))
{
System.out.println("Weather Station exited!!!");
System.exit(0);
}
updateMeasurement(sc.nextInt(), sc.nextInt(), sc.nextInt());
sc.nextLine();
}
}
private void updateMeasurement(int temperature, int humidity, int pressure) {
if(!data.equals(temperature, humidity, pressure)) {
Event e = getEvent(data.getTemperatureVar(temperature), data.getHumidityVar(humidity), data.getPressureVar(pressure));
data.update(temperature, humidity, pressure);
stashEvent(e);
}
}
private Event getEvent(int temperatureVar, int humidityVar, int pressureVar) {
return new WeatherDataChangeEvent(temperatureVar, humidityVar, pressureVar);
}
private void stashEvent(Event e) {
synchronized(events) {
System.out.println("[+++] Stash Event To Event List...");
events.add(e);
events.notify();
}
}
private void dispatch() {
Event event;
while(true) {
synchronized(events) {
while(events.isEmpty()) {
try {
events.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("\n[---] Remove Event From Event List...");
event = events.iterator().next();
events.remove(event);
}
dispatch(event);
}
}
private void dispatch(Event e) {
for(EventListener listener : listeners) {
listener.notifyEvent(e);
}
}
}
这里采用多线程实现了异步驱动,因为单线程下的异步驱动看不出明显的异步效果。与同步驱动的EventSource相比,异步驱动的EventSource增加了List<Event> events用于缓存Even。在方法updateMeasurement(int temperature, int humidity, int pressure)中生成Event后不再直接调用方法dispatch(Event e)通知EventListener,而是先调用方法stashEvent(Event e)将Event添加到List<Event> events中,然后另一个线程通过方法ispatch()挑选Even并通知EventListener。
测试类
public class SyncWeatherEventTest {
public static void main(String[] args) {
WeatherStation station = new WeatherStation();
station.addListener(new PressureListener());
station.addListener(new HumidityListener());
station.addListener(new TemperatureListener());
station.monitor();
}
}