Java設(shè)計模式中的觀察者模式
一.介紹
觀察者模式(Observer Pattern)屬于行為型模式。定義了對象之間的一對多依賴,讓多個觀察者同時監(jiān)聽某一個主題對象,類似于廣播機(jī)制,只需要分發(fā)廣播,感興趣的對象自動接收該廣播。我們平常所說的Observer、Listener、Hook、Callback都和這個模式有關(guān)
二.場景約束
小孩(Baby)哭的時候會通知到爸爸(Dad)和媽媽(Mum),爸爸媽媽會對此采取不同的行為
三.UML類圖
版本一

版本二
新增事件類將觀察者與主題解耦,觀察者可以根據(jù)不同的事件執(zhí)行不同的操作,也可以直接對事件源進(jìn)行操作

四.示意代碼(版本一)
業(yè)務(wù)代碼
//抽象觀察者
public interface Observer {
void action();
}
//抽象主題
abstract class Subject{
protected List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public abstract void notifyObserver();
}
//具體主題-被觀察者
class Baby extends Subject{
@Override
public void notifyObserver() {
System.out.println("baby cry");
observers.forEach(Observer::action);
}
}
//具體觀察者
class Dad implements Observer {
@Override
public void action() {
System.out.println("dad feed baby");
}
}
//具體觀察者
class Mum implements Observer {
@Override
public void action() {
System.out.println("mum hug baby");
}
}
客戶端
public class Client {
public static void main(String[] args) {
Baby baby = new Baby();
baby.addObserver(new Mum());
baby.addObserver(new Dad());
baby.notifyObserver();
}
}
五.示意代碼(版本二)
//抽象觀察者
public interface Observer {
void action(Event event);
}
//抽象主題
abstract class Subject {
protected List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public abstract void notifyObserver();
}
//具體主題-被觀察者
class Baby extends Subject {
@Override
public void notifyObserver() {
System.out.println("baby cry");
CryEvent cryEvent = new CryEvent(new Date().getTime(), this);
observers.forEach(observer -> observer.action(cryEvent));
}
}
//抽象事件
abstract class Event {
public abstract Object getSource();
}
//具體事件
class CryEvent extends Event {
public long when;
Baby source;
public CryEvent(long when, Baby source) {
this.when = when;
this.source = source;
}
@Override
public Baby getSource() {
return source;
}
}
//具體觀察者
class Dad implements Observer {
@Override
public void action(Event event) {
System.out.println("dad feed baby");
if(event.getSource() instanceof Baby){
System.out.println("dad對事件源進(jìn)行處理");
}
}
}
//具體觀察者
class Mum implements Observer {
@Override
public void action(Event event) {
System.out.println("mum hug baby");
if(event.getSource() instanceof Baby){
System.out.println("mum對事件源進(jìn)行處理");
}
}
}
客戶端
public class Client {
public static void main(String[] args) {
Baby baby = new Baby();
baby.addObserver(new Dad());
baby.addObserver(new Mum());
baby.notifyObserver();
}
}
六.觀察者模式與發(fā)布訂閱模式

發(fā)布訂閱模式
- 發(fā)布者不會直接通知訂閱者
- 發(fā)布者與訂閱者完全解耦
觀察者模式
- 主題要自己通知(notify)觀察者
- 主題與觀察者松耦合
七.優(yōu)點(diǎn)
- 符合依賴倒置原則(觀察者與主題都依賴于抽象)
- 降低耦合(主題與觀察者之間的耦合關(guān)系)
八.在JDK中的典型應(yīng)用
在java.awt包下有很多觀察者模式的身影,先來看下簡單的UML類圖
主題角色:java提供的組件類(以Button為例) 觀察者角色:java提供的事件監(jiān)聽(各種Listener) 事件角色:鼠標(biāo)事件、鍵盤事件等等

再來看看一個小demo 在窗口中添加一個按鈕,給按鈕添加上鼠標(biāo)與鍵盤的相關(guān)事件,當(dāng)點(diǎn)擊按鈕或者按下鍵盤的時候在控制臺打印相應(yīng)的語句
public class MainFrame extends JFrame {
public MainFrame() throws HeadlessException {
//定義一個具體主題
Button button = new Button("click");
//給主題添加觀察者(鼠標(biāo)監(jiān)聽)
button.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
//MouseEvent就是具體事件
System.out.println("按鈕被點(diǎn)擊");
}
});
//給主題添加觀察者(鍵盤監(jiān)聽)
button.addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
//KeyEvent就是具體事件
System.out.println("按下" + e.getKeyChar());
}
});
add(button);
setSize(100,100);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public static void main(String[] args) {
new MainFrame();
}
}
這里的KeyAdapter與MouseAdapter使用的是適配器模式
到此這篇關(guān)于Java設(shè)計模式中的觀察者模式的文章就介紹到這了,更多相關(guān)Java觀察者模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
完美解決MybatisPlus插件分頁查詢不起作用總是查詢?nèi)繑?shù)據(jù)問題
這篇文章主要介紹了解決MybatisPlus插件分頁查詢不起作用總是查詢?nèi)繑?shù)據(jù)問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08
SpringCloud解決feign調(diào)用token丟失問題解決辦法
在feign調(diào)用中可能會遇到如下問題:同步調(diào)用中,token丟失,這種可以通過創(chuàng)建一個攔截器,將token做透傳來解決,異步調(diào)用中,token丟失,這種就無法直接透傳了,因為子線程并沒有token,這種需要先將token從父線程傳遞到子線程,再進(jìn)行透傳2024-05-05
Spring?WebMVC初始化Controller流程詳解
這篇文章主要介紹了Spring?WebMVC初始化Controller流程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02
Spring Boot實現(xiàn)分布式鎖的自動釋放的示例代碼
在實際開發(fā)中,我們可以使用 Redis、Zookeeper 等分布式系統(tǒng)來實現(xiàn)分布式鎖,本文將介紹如何使用 Spring Boot 來實現(xiàn)分布式鎖的自動釋放,感興趣的朋友跟隨小編一起看看吧2023-06-06
Java使用AOP技術(shù)實現(xiàn)通用接口驗簽工具
這篇文章主要為大家詳細(xì)介紹了Java如何使用AOP技術(shù)實現(xiàn)通用接口驗簽工具,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下吧2025-03-03
JAVA中字符串函數(shù)subString的用法小結(jié)
本篇文章主要是對JAVA中字符串函數(shù)subString的用法進(jìn)行了詳細(xì)的介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-02-02
詳解如何將JAVA程序制作成可以直接執(zhí)行的exe文件
這篇文章主要介紹了詳解如何將JAVA程序制作成可以直接執(zhí)行的exe文件,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09

