一、觀察者模式的應用場景
生活中的微信朋友圈動態通知、工作中的郵件通知、學校操場上的廣播通知、電腦桌面應用程序的事件響應等等,這些都是觀察者模式的現實生活場景。觀察者模式(Observer Pattern)定義了對象之間一對多的依賴,讓多個觀察者監聽一個主體對象,當主體對象發生變化時,它的所有觀察者都會收到通知並且更新。
觀察者模式也叫發佈訂閱模式。1.1 學生在線提問的案例
現在還是新冠狀病毒疫情期間,很多學生在家裡學習遇到問題,難免需要請教自己的老師,當學生在某教育平臺上提問的時候,如果有設置指定的老師進行答覆,那麼對應的老師會受到相應的郵件通知,這就是觀察者模式的一種應用場景。拿到這個需要的時候我們可能會想到異步隊列、消息中間件MQ等一些技術手段,其實JDK本身就提供了這樣的API,那麼我們來寫關於這個場景的示例代碼,創建 Question 問題類:
<code>public class Question {
private String userName;
private String content;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
/<code>
再創建教育平臺被觀察者 Education 類繼承 Observable :
<code>public class Education extends Observable {
private final String EDU_NAME = "xxx互聯網教育平臺";
private Education() {}
private static Education education = null;
public static Education getInstance() {
if(null == education) {
education = new Education();
}
return education;
}
public void publishQuestion(Question question) {
System.out.println(question.getUserName() + "在" + EDU_NAME + "上提交了一個問題!");
this.setChanged();
this.notifyObservers(question);
}
}
/<code>
創建老師 Teacher 類實現 Observer接口:
<code>public class Teacher implements Observer {
private String name;
public Teacher(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
Education education = (Education) o;
Question question = (Question) arg;
System.out.println("===============================");
System.out.println(name + "老師,你好!\\n" +
"您收到了一個來自“" + education.getEduName() + "”的提問,希望您解答,問題內容如下:\\n" +
question.getContent() + "\\n" +
"提問者:" + question.getUserName());
}
}
/<code>
測試main方法:
<code> public static void main(String[] args) {
Education edu = Education.getInstance();
Teacher teacher1 = new Teacher("Kevin");
Teacher teacher2 = new Teacher("Jhon");
edu.addObserver(teacher1);
edu.addObserver(teacher2);
Question question = new Question();
question.setUserName("小芳");
question.setContent("觀察者模式有哪些應用場景?");
edu.publishQuestion(question);
}
/<code>
測試運行結果:
二、觀察者模式在源碼中的體現
2.1 Spring中的ContextLoaderListener
Spring中的ContextLoaderListener實現了ServletContextListener接口,ServletContextListener又繼承了EventListener,我們來看下ContextLoaderListener源碼:
<code>public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {
}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
public void contextInitialized(ServletContextEvent event) {
this.initWebApplicationContext(event.getServletContext());
}
public void contextDestroyed(ServletContextEvent event) {
this.closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
/<code>
ServletContextListener :
<code>public interface ServletContextListener extends EventListener {
default void contextInitialized(ServletContextEvent sce) {
}
default void contextDestroyed(ServletContextEvent sce) {
}
}
/<code>
EventListener :
<code>/**
* A tagging interface that all event listener interfaces must extend.
* @since JDK1.1
*/
public interface EventListener {
}
/<code>
2.2 基於Guava API實現觀察者模式
pom依賴
<code><dependency>
\t<groupid>com.google.guava/<groupid>
\t<artifactid>guava/<artifactid>
\t<version>23.0/<version>
/<dependency>
/<code>
創建監聽事件GuavaEvent:
<code>public class GuavaEvent {
@Subscribe
public void subscrible(String str) {
System.out.println("執行subscrible方法,傳入的參數是:" + str);
}
}
/<code>
測試main方法:
<code>public static void main(String[] args) {
EventBus eventBus = new EventBus();
GuavaEvent guavaEvent = new GuavaEvent();
eventBus.register(guavaEvent);
eventBus.post("Kevin");
}
/<code>
三、觀察者模式的優缺點
優點:
- 觀察者和被觀察者之間建立了一個抽象的耦合;
- 觀察者模式支持廣播通信。
缺點:
- 觀察者之間有過多的細節依賴、提高時間消耗及程序的複雜度;
- 使用要得當,要避免循環調用。
閱讀更多 來一杯咖啡 的文章