Java設(shè)計(jì)模式中的觀察者模式
一.介紹
觀察者模式(Observer Pattern)屬于行為型模式。定義了對(duì)象之間的一對(duì)多依賴,讓多個(gè)觀察者同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象,類似于廣播機(jī)制,只需要分發(fā)廣播,感興趣的對(duì)象自動(dòng)接收該廣播。我們平常所說(shuō)的Observer、Listener、Hook、Callback都和這個(gè)模式有關(guān)
二.場(chǎng)景約束
小孩(Baby)哭的時(shí)候會(huì)通知到爸爸(Dad)和媽媽(Mum),爸爸媽媽會(huì)對(duì)此采取不同的行為
三.UML類圖
版本一
版本二
新增事件類將觀察者與主題解耦,觀察者可以根據(jù)不同的事件執(zhí)行不同的操作,也可以直接對(duì)事件源進(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對(duì)事件源進(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對(duì)事件源進(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ā)布者不會(huì)直接通知訂閱者
- 發(fā)布者與訂閱者完全解耦
觀察者模式
- 主題要自己通知(notify)觀察者
- 主題與觀察者松耦合
七.優(yōu)點(diǎn)
- 符合依賴倒置原則(觀察者與主題都依賴于抽象)
- 降低耦合(主題與觀察者之間的耦合關(guān)系)
八.在JDK中的典型應(yīng)用
在java.awt包下有很多觀察者模式的身影,先來(lái)看下簡(jiǎn)單的UML類圖
主題角色:java提供的組件類(以Button為例) 觀察者角色:java提供的事件監(jiān)聽(tīng)(各種Listener) 事件角色:鼠標(biāo)事件、鍵盤事件等等
再來(lái)看看一個(gè)小demo 在窗口中添加一個(gè)按鈕,給按鈕添加上鼠標(biāo)與鍵盤的相關(guān)事件,當(dāng)點(diǎn)擊按鈕或者按下鍵盤的時(shí)候在控制臺(tái)打印相應(yīng)的語(yǔ)句
public class MainFrame extends JFrame { public MainFrame() throws HeadlessException { //定義一個(gè)具體主題 Button button = new Button("click"); //給主題添加觀察者(鼠標(biāo)監(jiān)聽(tīng)) button.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { //MouseEvent就是具體事件 System.out.println("按鈕被點(diǎn)擊"); } }); //給主題添加觀察者(鍵盤監(jiān)聽(tīng)) 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è)計(jì)模式中的觀察者模式的文章就介紹到這了,更多相關(guān)Java觀察者模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot如何集成jodconverter做文檔轉(zhuǎn)換
這篇文章主要介紹了Springboot如何集成jodconverter做文檔轉(zhuǎn)換問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08Java接收text/event-stream格式數(shù)據(jù)的詳細(xì)代碼
這篇文章主要介紹了java接收text/event-stream格式數(shù)據(jù),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07關(guān)于thymeleaf判斷對(duì)象是否為空的相關(guān)邏輯處理
這篇文章主要介紹了關(guān)于thymeleaf判斷對(duì)象是否為空的相關(guān)邏輯處理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10Spring如何通過(guò)注解引入外部資源(PropertySource?Value)
這篇文章主要為大家介紹了Spring通過(guò)注解@PropertySource和@Value引入外部資源的方法實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07