java觀察者模式實(shí)現(xiàn)和java觀察者模式演化
簡(jiǎn)單的觀察者模式實(shí)現(xiàn)
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* 觀察者模式中用到了回調(diào):
* A. 觀察者將自己注冊(cè)到被觀察者的監(jiān)聽(tīng)者列表,且觀察者類自身提供了一個(gè)回調(diào)函數(shù)
* B. 被觀察者(Observable或Subject)維護(hù)觀察者列表,并且可以注冊(cè)和解注冊(cè)觀察者
* C. 一旦被觀察者狀態(tài)發(fā)生改變,它可以調(diào)用notifyObservers(),這個(gè)方法將遍歷觀察者列表并逐個(gè)調(diào)用
觀察者提供的回調(diào)函數(shù)
* @author will
*
*/
public class SimpleObserverPattern {
public static void main(String[] args) {
SimpleObserverPattern sop = new SimpleObserverPattern();
List<IObserver> observers = new ArrayList<IObserver> ();
IObserver observerA = sop.new Observer("ObserverA");
IObserver observerB = sop.new Observer("ObserverB");
observers.add(observerA);
observers.add(observerB);
IObservable observable = sop.new Observable(observers);
observable.registerObserver(sop.new Observer("ObserverC"));
observable.changeState();
observable.close();
}
// 被觀察者,有的地方叫Subject
interface IObservable {
void registerObserver(IObserver observer);
void unregisterObserver(IObserver observer);
void notifyObservers();
String getState();
void changeState();
void close();
}
class Observable implements IObservable {
private static final String NEW = "New";
private static final String CHANGED = "Changed";
private static final String CLOSED = "Closed";
private String state;
private List<IObserver> observers;
public Observable() {
this(null);
}
public Observable(List<IObserver> observers) {
if(observers == null) {
observers = new ArrayList<IObserver> ();
}
this.observers = Collections.synchronizedList(observers);
this.state = NEW;
}
@Override
public void registerObserver(IObserver observer) {
observers.add(observer);
}
@Override
public void unregisterObserver(IObserver observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
Iterator<IObserver> iter = observers.iterator();
while(iter.hasNext()) {
iter.next().update(this);
}
}
@Override
public String getState() {
return state;
}
@Override
public void changeState() {
this.state = CHANGED;
notifyObservers();
}
@Override
public void close() {
this.state = CLOSED;
notifyObservers();
}
}
interface IObserver {
void update(IObservable observalbe);
}
class Observer implements IObserver {
private String name;
public Observer(String name) {
this.name = name;
}
@Override
public void update(IObservable observalbe) {
System.out.println(
String.format("%s receive observalbe's change, current observalbe's state is %s",
name, observalbe.getState()));
}
}
}
上面的實(shí)現(xiàn)直接將被觀察者對(duì)象作為回調(diào)函數(shù)參數(shù),這樣做很不優(yōu)雅,在簡(jiǎn)單的場(chǎng)景可能奏效。
但事實(shí)上更多情況下,一個(gè)被觀察者有很多種事件或者狀態(tài),而每個(gè)觀察者可能感興趣的事件或狀態(tài)都不相同,或者為了信息隱藏的目的,不想讓每個(gè)觀察者都能訪問(wèn)到Observable內(nèi)部的所有狀態(tài)。
這樣我繼續(xù)演化代碼為下面這個(gè)版本,注意我這里沒(méi)有很細(xì)致地考慮并發(fā)問(wèn)題。
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
public class MultiEventObserverPattern {
public static void main(String[] args) {
MultiEventObserverPattern meop = new MultiEventObserverPattern();
IObservable observable = meop.new Observable();
IObserver observerA = meop.new Observer("ObserverA");
IObserver observerB = meop.new Observer("ObserverB");
// 注冊(cè)感興趣的事件
observable.registerObserver(observable.getEventA(), observerA);
observable.registerObserver(observable.getEventB(), observerB);
// 改變被觀察者狀態(tài)
observable.changeStateA();
observable.changeStateB();
}
interface IEvent {
void eventChange();
String getState();
}
class EventA implements IEvent {
private static final String INITIALIZED = "Initialized";
private static final String PENDING = "Pending";
private String state;
public EventA() {
this.state = INITIALIZED;
}
@Override
public void eventChange() {
System.out.println("EventA change");
this.state = PENDING;
}
@Override
public String toString() {
return "EventA";
}
@Override
public String getState() {
return state;
}
}
class EventB implements IEvent {
private static final String NEW = "New";
private static final String IDLE = "Idle";
private String state;
public EventB() {
this.state = NEW;
}
@Override
public void eventChange() {
System.out.println("EventB change");
this.state = IDLE;
}
@Override
public String toString() {
return "EventB";
}
@Override
public String getState() {
return state;
}
}
// 被觀察者(Observable),有的地方叫Subject
interface IObservable {
void registerObserver(IEvent event, IObserver observer);
void unregisterObserver(IEvent event, IObserver observer);
// 通知觀察者某個(gè)事件發(fā)生了
void notifyObservers(IEvent event);
void changeStateA();
void changeStateB();
IEvent getEventA();
IEvent getEventB();
}
class Observable implements IObservable {
private IEvent eventA;
private IEvent eventB;
private Hashtable<IEvent, Set<IObserver>> eventObserverMapping;
public Observable() {
this(null);
}
// 這里如果evenObserverMapping傳入的某些Set<IObserver>是未被同步修飾的,那么也沒(méi)辦法
public Observable(Hashtable<IEvent, Set<IObserver>> eventObserverMapping) {
if(eventObserverMapping == null) {
eventObserverMapping = new Hashtable<IEvent, Set<IObserver>> ();
}
this.eventObserverMapping = new Hashtable<IEvent, Set<IObserver>> ();
this.eventA = new EventA();
this.eventB = new EventB();
}
@Override
public void registerObserver(IEvent event, IObserver observer) {
Set<IObserver> observers = eventObserverMapping.get(event);
if(observers == null) {
observers = Collections.synchronizedSet(new HashSet<IObserver> ());
observers.add(observer);
eventObserverMapping.put(event, observers);
}
else {
observers.add(observer);
}
}
@Override
public void unregisterObserver(IEvent event, IObserver observer) {
Set<IObserver> observers = eventObserverMapping.get(event);
if(observers != null) {
observers.remove(observer);
}
}
@Override
public void notifyObservers(IEvent event) {
Set<IObserver> observers = eventObserverMapping.get(event);
if(observers != null && observers.size() > 0) {
Iterator<IObserver> iter = observers.iterator();
while(iter.hasNext()) {
iter.next().update(event);
}
}
}
@Override
public void changeStateA() {
// 改變狀態(tài)A會(huì)觸發(fā)事件A
eventA.eventChange();
notifyObservers(eventA);
}
@Override
public void changeStateB() {
// 改變狀態(tài)B會(huì)觸發(fā)事件B
eventB.eventChange();
notifyObservers(eventB);
}
@Override
public IEvent getEventA() {
return eventA;
}
@Override
public IEvent getEventB() {
return eventB;
}
}
interface IObserver {
void update(IEvent event);
}
class Observer implements IObserver {
private String name;
public Observer(String name) {
this.name = name;
}
@Override
public void update(IEvent event) {
System.out.println(
String.format("%s receive %s's change, current observalbe's state is %s",
name, event, event.getState()));
}
}
}
似乎看起來(lái)挺完美了,但還是不夠完美。因?yàn)槭录挥簿幋a為被觀察者類的屬性。這樣事件類型在編譯時(shí)期就被定死了,如果要增加新的事件類型就不得不修改IObservable接口和Observable類,這大大削減了靈活性。
相當(dāng)于被觀察者耦合于這些具體的事件,那么我們?nèi)绾蝸?lái)打破這個(gè)限制呢?
答案是引入一個(gè)新的組件,讓那個(gè)組件來(lái)管理事件、觀察者、被觀察者之間的關(guān)系,事件發(fā)生時(shí)也由那個(gè)組件來(lái)調(diào)用觀察者的回調(diào)函數(shù)。這也是一種解耦吧,有點(diǎn)類似Spring的IOC容器。
至于具體實(shí)現(xiàn),我覺(jué)得Guava EventBus做得已經(jīng)蠻好了,可以參考我前面提到的鏈接。
PS:本帖不是為Guava EventBus做廣告,只是自己的思路一步步推進(jìn),逐漸地就和Guava EventBus的設(shè)計(jì)思路吻合了。
下面繼續(xù)看看JDK標(biāo)準(zhǔn)類實(shí)現(xiàn)觀察者模式的例子,然后分析下它的源碼實(shí)現(xiàn),要看的只有一個(gè)Observable類和一個(gè)Observer接口。
JDK標(biāo)準(zhǔn)類實(shí)現(xiàn)觀察者模式
import java.util.Observable;
import java.util.Observer;
/**
* 使用java.util包中的標(biāo)準(zhǔn)類實(shí)現(xiàn)觀察者模式
* @author will
*
*/
public class JDKObserverDemo {
public static void main(String[] args) {
JDKObserverDemo jod = new JDKObserverDemo();
// 被觀察者
MyObservable myObservable = jod.new MyObservable("hello");
// 觀察者
Observer myObserver = jod.new MyObserver();
// 注冊(cè)
myObservable.addObserver(myObserver);
// 改變被觀察者狀態(tài),觸發(fā)觀察者回調(diào)函數(shù)
myObservable.setValue("will");
}
class MyObservable extends Observable {
private String watchedValue; // 被觀察的值
public MyObservable(String watchedValue) {
this.watchedValue = watchedValue;
}
public void setValue(String newValue) {
if(!watchedValue.equals(newValue)) {
watchedValue = newValue;
setChanged();
notifyObservers(newValue);
}
}
@Override
public String toString() {
return "MyObservable";
}
}
class MyObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println(o + "'s state changed, argument is: " + arg);
}
}
}
看了下JDK標(biāo)準(zhǔn)庫(kù)中的Observer和Observable實(shí)現(xiàn)很簡(jiǎn)單,不想多說(shuō)了。
下面是Quartz中的監(jiān)聽(tīng)器實(shí)現(xiàn)。
QuartzScheduler被監(jiān)聽(tīng)者
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Quartz核心類,相當(dāng)于Observable(被觀察者)
* @author will
*
*/
public class QuartzScheduler {
private ArrayList<SchedulerListener> internalSchedulerListeners = new ArrayList<SchedulerListener>(10);
// private ArrayList<JobListener> interanlJobListeners = new ArrayList<JobListener>(); // 一個(gè)Observable可以包含多組監(jiān)聽(tīng)器
public Date scheduleJob(Trigger trigger) {
if(trigger == null) {
return null;
}
System.out.println("Schedule job, trigger: " + trigger);
notifySchedulerListenersScheduled(trigger);
return new Date();
}
public void unScheduleJob(Trigger trigger) {
if(trigger == null) {
return;
}
System.out.println("Unschedule job, trigger: " + trigger);
notifyShedulerListenerUnScheduled(trigger);
}
// 注冊(cè)SchedulerListener
public void addInternalSchedulerListener(SchedulerListener schedulerListener) {
synchronized (internalSchedulerListeners) {
internalSchedulerListeners.add(schedulerListener);
}
}
// 移除SchedulerListener
public boolean removeInternalSchedulerListener(SchedulerListener schedulerListener) {
synchronized (internalSchedulerListeners) {
return internalSchedulerListeners.remove(schedulerListener);
}
}
public List<SchedulerListener> getInternalSchedulerListeners() {
synchronized (internalSchedulerListeners) {
return java.util.Collections.unmodifiableList(new ArrayList<SchedulerListener>(internalSchedulerListeners));
}
}
public void notifySchedulerListenersScheduled(Trigger trigger) {
for(SchedulerListener listener: getInternalSchedulerListeners()) {
listener.jobScheduled(trigger);
}
}
public void notifyShedulerListenerUnScheduled(Trigger trigger) {
for(SchedulerListener listener: getInternalSchedulerListeners()) {
listener.jobUnScheduled(trigger);
}
}
}
SchedulerListener
// 監(jiān)聽(tīng)接口,回調(diào)函數(shù),Client注冊(cè)監(jiān)聽(tīng)時(shí)需要提供回調(diào)函數(shù)實(shí)現(xiàn)
public interface SchedulerListener {
void jobScheduled(Trigger trigger);
void jobUnScheduled(Trigger trigger);
}
Trigger
// Trigger
public class Trigger {
private String triggerKey;
private String triggerName;
public Trigger(String triggerKey, String triggerName) {
this.triggerKey = triggerKey;
this.triggerName = triggerName;
}
public String getTriggerKey() {
return triggerKey;
}
public void setTriggerKey(String triggerKey) {
this.triggerKey = triggerKey;
}
public String getTriggerName() {
return triggerName;
}
public void setTriggerName(String triggerName) {
this.triggerName = triggerName;
}
public String toString() {
return String.format("{triggerKey: %s, triggerName: %s}", triggerKey, triggerName);
}
}
Test
public class Test {
public static void main(String[] args) {
QuartzScheduler qs = new QuartzScheduler();
SchedulerListener listenerA = new SchedulerListener() {
@Override
public void jobUnScheduled(Trigger trigger) {
System.out.println("listenerA job unscheduled: " + trigger.getTriggerName());
}
@Override
public void jobScheduled(Trigger trigger) {
System.out.println("listenerA job scheduled: " + trigger.getTriggerName());
}
};
SchedulerListener listenerB = new SchedulerListener() {
@Override
public void jobUnScheduled(Trigger trigger) {
System.out.println("listenerB job unscheduled: " + trigger.getTriggerName());
}
@Override
public void jobScheduled(Trigger trigger) {
System.out.println("listenerB job scheduled: " + trigger.getTriggerName());
}
};
// 注冊(cè)Scheduler Listener
qs.addInternalSchedulerListener(listenerA);
qs.addInternalSchedulerListener(listenerB);
Trigger triggerA = new Trigger("Key1", "triggerA");
Trigger triggerB = new Trigger("Key2", "triggerB");
qs.scheduleJob(triggerA);
qs.scheduleJob(triggerB);
qs.unScheduleJob(triggerA);
}
}
相關(guān)文章
Spring?Security+JWT簡(jiǎn)述(附源碼)
SpringSecurity是一個(gè)強(qiáng)大的可高度定制的認(rèn)證和授權(quán)框架,對(duì)于Spring應(yīng)用來(lái)說(shuō)它是一套Web安全標(biāo)準(zhǔn),下面這篇文章主要給大家介紹了關(guān)于Spring?Security+JWT簡(jiǎn)述的相關(guān)資料,需要的朋友可以參考下2023-04-04Java實(shí)現(xiàn)二叉樹(shù)的基本操作詳解
這篇文章主要為大家詳細(xì)介紹了Java數(shù)據(jù)結(jié)構(gòu)與算法中二叉樹(shù)的基本操作,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下2022-10-10JAVA面試題之Forward與Redirect的區(qū)別詳解
這篇文章主要給大家介紹了在JAVA面試中可能遇到會(huì)遇到的一道題,就是java中Forward與Redirect兩者之前的區(qū)別,文中介紹的非常詳細(xì),對(duì)大家具有一定參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-05-05Java設(shè)計(jì)模式之原型模式詳細(xì)解析
這篇文章主要介紹了Java設(shè)計(jì)模式之原型模式詳細(xì)解析,原型模式就是用一個(gè)已經(jīng)創(chuàng)建的實(shí)例作為原型,通過(guò)復(fù)制該原型對(duì)象來(lái)創(chuàng)建一個(gè)和原型對(duì)象相同的新對(duì)象,需要的朋友可以參考下2023-11-11Mybatis中TypeAliasRegistry的作用及使用方法
Mybatis中的TypeAliasRegistry是一個(gè)類型別名注冊(cè)表,它的作用是為Java類型建立別名,使得在Mybatis配置文件中可以使用別名來(lái)代替完整的Java類型名。使用TypeAliasRegistry可以簡(jiǎn)化Mybatis配置文件的編寫,提高配置文件的可讀性和可維護(hù)性2023-05-05SpringBoot實(shí)現(xiàn)JWT token自動(dòng)續(xù)期的示例代碼
本文主要介紹了SpringBoot實(shí)現(xiàn)JWT token自動(dòng)續(xù)期的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01SpringSecurity從數(shù)據(jù)庫(kù)中獲取用戶信息進(jìn)行驗(yàn)證的案例詳解
這篇文章主要介紹了SpringSecurity從數(shù)據(jù)庫(kù)中獲取用戶信息進(jìn)行驗(yàn)證的案例詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01