Java設(shè)計(jì)模式開發(fā)中使用觀察者模式的實(shí)例教程
觀察者模式是軟件設(shè)計(jì)模式中的一種,使用也比較普遍,尤其是在GUI編程中。關(guān)于設(shè)計(jì)模式的文章,網(wǎng)絡(luò)上寫的都比較多,而且很多文章寫的也不錯(cuò),雖然說(shuō)有一種重復(fù)早輪子的嫌疑,但此輪子非彼輪子,側(cè)重點(diǎn)不同,思路也不同,講述方式也不近相同。
關(guān)鍵要素
主題:
主題是觀察者觀察的對(duì)象,一個(gè)主題必須具備下面三個(gè)特征。
- 持有監(jiān)聽的觀察者的引用
- 支持增加和刪除觀察者
- 主題狀態(tài)改變,通知觀察者
觀察者:
當(dāng)主題發(fā)生變化,收到通知進(jìn)行具體的處理是觀察者必須具備的特征。
為什么要用這種模式
這里舉一個(gè)例子來(lái)說(shuō)明,牛奶送奶站就是主題,訂奶客戶為監(jiān)聽者,客戶從送奶站訂閱牛奶后,會(huì)每天收到牛奶。如果客戶不想訂閱了,可以取消,以后就不會(huì)收到牛奶。
松耦合
觀察者增加或刪除無(wú)需修改主題的代碼,只需調(diào)用主題對(duì)應(yīng)的增加或者刪除的方法即可。
主題只負(fù)責(zé)通知觀察者,但無(wú)需了解觀察者如何處理通知。舉個(gè)例子,送奶站只負(fù)責(zé)送遞牛奶,不關(guān)心客戶是喝掉還是洗臉。
觀察者只需等待主題通知,無(wú)需觀察主題相關(guān)的細(xì)節(jié)。還是那個(gè)例子,客戶只需關(guān)心送奶站送到牛奶,不關(guān)心牛奶由哪個(gè)快遞人員,使用何種交通工具送達(dá)。
Java實(shí)現(xiàn)觀察者模式
1. Java自帶的實(shí)現(xiàn)
類圖

/**
* 觀察目標(biāo) 繼承自 java.util.Observable
* @author stone
*
*/
public class UpdateObservable extends Observable {
private int data;
public UpdateObservable(Observer observer) {
addObserver(observer);
/*
* add other observer
*/
}
public int getData() {
return data;
}
public void setData(int data) {
if (data != this.data) {
this.data = data;
setChanged(); //標(biāo)記 改變, 只有標(biāo)記后才能通知到
notifyObservers(); //通知
}
}
@Override
public synchronized void addObserver(Observer o) {
super.addObserver(o);
}
@Override
public synchronized void deleteObserver(Observer o) {
super.deleteObserver(o);
}
@Override
public void notifyObservers() {
super.notifyObservers();
}
@Override
public void notifyObservers(Object arg) {
super.notifyObservers(arg);
}
@Override
public synchronized void deleteObservers() {
super.deleteObservers();
}
@Override
protected synchronized void setChanged() {
super.setChanged();
}
@Override
protected synchronized void clearChanged() {
super.clearChanged();
}
@Override
public synchronized boolean hasChanged() {
return super.hasChanged();
}
@Override
public synchronized int countObservers() {
return super.countObservers();
}
}
/**
* 觀察者 實(shí)現(xiàn) java.util.Observer接口
* @author stone
*
*/
public class UpdateObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("接收到數(shù)據(jù)變化的通知:");
if (o instanceof UpdateObservable) {
UpdateObservable uo = (UpdateObservable) o;
System.out.print("數(shù)據(jù)變更為:" + uo.getData());
}
}
}
2. 自定義的觀察模型
類圖

/**
* 抽象觀察者 Observer
* 觀察 更新
* @author stone
*
*/
public interface IWatcher {
/*
* 通知接口:
* 1. 簡(jiǎn)單通知
* 2. 觀察者需要目標(biāo)的變化的數(shù)據(jù),那么可以將目標(biāo)用作參數(shù), 見Java的Observer和Observable
*/
// void update(IWatched watched);
void update();
}
/**
* 抽象目標(biāo) Subject
* 提供注冊(cè)和刪除觀察者對(duì)象的接口, 及通知觀察者進(jìn)行觀察的接口
* 及目標(biāo) 自身被觀察的業(yè)務(wù)的接口
* @author stone
*
*/
public interface IWatchedSubject {
public void add(IWatcher watch);
public void remove(IWatcher watch);
public void notifyWhatchers();
public void update();//被觀察業(yè)務(wù)變化的接口
}
/**
* 具體觀察者 Concrete Observer
*
* @author stone
*
*/
public class UpdateWatcher implements IWatcher {
@Override
public void update() {
System.out.println(this + "觀察到:目標(biāo)已經(jīng)更新了");
}
}
/**
* 具體目標(biāo)角色 Concrete Subject
* @author stone
*
*/
public class UpdateWatchedSubject implements IWatchedSubject {
private List<IWatcher> list;
public UpdateWatchedSubject() {
this.list = new ArrayList<IWatcher>();
}
@Override
public void add(IWatcher watch) {
this.list.add(watch);
}
@Override
public void remove(IWatcher watch) {
this.list.remove(watch);
}
@Override
public void notifyWhatchers() {
for (IWatcher watcher : list) {
watcher.update();
}
}
@Override
public void update() {
System.out.println("目標(biāo)更新中....");
notifyWhatchers();
}
}
監(jiān)聽器是觀察者的一種實(shí)現(xiàn):
類圖

/**
* 監(jiān)聽 用戶在注冊(cè)后
* @author stone
*
*/
public interface IRegisterListener {
void onRegistered();
}
/**
* 監(jiān)聽 當(dāng)用戶登錄后
* @author stone
*
*/
public interface ILoginListener {
void onLogined();
}
/*
* 監(jiān)聽器 是觀察者模式的一種實(shí)現(xiàn)
* 一些需要監(jiān)聽的業(yè)務(wù)接口上添加 監(jiān)聽器,調(diào)用監(jiān)聽器的相應(yīng)方法,實(shí)現(xiàn)監(jiān)聽
*/
public class User {
public void register(IRegisterListener register) {
/*
* do ... register
*/
System.out.println("正在注冊(cè)中...");
//注冊(cè)后
register.onRegistered();
}
public void login(ILoginListener login) {
/*
* do ... login
*/
System.out.println("正在登錄中...");
//登錄后
login.onLogined();
}
}
/**
* 觀察者(Observer)模式 行為型模式
* 觀察者模式定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)觀察某一個(gè)目標(biāo)對(duì)象。
* 這個(gè)目標(biāo)對(duì)象在狀態(tài)上發(fā)生變化時(shí),會(huì)通知所有觀察者對(duì)象,讓它們能夠自動(dòng)更新自己
* 目標(biāo)對(duì)象中需要有添加、移除、通知 觀察者的接口
*
* @author stone
*/
public class Test {
public static void main(String[] args) {
/*
* 使用Java自帶的Observer接口和Observable類
*/
UpdateObservable observable = new UpdateObservable(new UpdateObserver());
observable.setData(99);
System.out.println("");
System.out.println("");
/*
* 自定義的觀察者模型
*/
IWatchedSubject watched = new UpdateWatchedSubject();
watched.add(new UpdateWatcher());
watched.add(new UpdateWatcher());
watched.update();
System.out.println("");
/*
* 子模式-監(jiān)聽器
*/
User user = new User();
user.register(new IRegisterListener() {
@Override
public void onRegistered() {
System.out.println("監(jiān)聽到注冊(cè)后。。。");
}
});
user.login(new ILoginListener() {
@Override
public void onLogined() {
System.out.println("監(jiān)聽到登錄后。。。");
}
});
}
}
打印
接收到數(shù)據(jù)變化的通知: 數(shù)據(jù)變更為:99 目標(biāo)更新中.... observer.UpdateWatcher@457471e0觀察到:目標(biāo)已經(jīng)更新了 observer.UpdateWatcher@5fe04cbf觀察到:目標(biāo)已經(jīng)更新了 正在注冊(cè)中... 監(jiān)聽到注冊(cè)后。。。 正在登錄中... 監(jiān)聽到登錄后。。。
- Java通俗易懂系列設(shè)計(jì)模式之觀察者模式
- Java設(shè)計(jì)模式之觀察者模式原理與用法詳解
- JAVA中常用的設(shè)計(jì)模式:?jiǎn)卫J?,工廠模式,觀察者模式
- Java設(shè)計(jì)模式—觀察者模式詳解
- 23種設(shè)計(jì)模式(13)java觀察者模式
- Java設(shè)計(jì)模式之觀察者模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
- Java經(jīng)典設(shè)計(jì)模式之觀察者模式原理與用法詳解
- java設(shè)計(jì)模式之觀察者模式學(xué)習(xí)
- java設(shè)計(jì)模式之觀察者模式
- 實(shí)例解析觀察者模式及其在Java設(shè)計(jì)模式開發(fā)中的運(yùn)用
- Java設(shè)計(jì)模式之觀察者模式(Observer模式)
相關(guān)文章
SpringBoot項(xiàng)目application.yml文件數(shù)據(jù)庫(kù)配置密碼加密的方法
這篇文章主要介紹了SpringBoot項(xiàng)目application.yml文件數(shù)據(jù)庫(kù)配置密碼加密的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
Spring Boot集成Swagger2項(xiàng)目實(shí)戰(zhàn)
在日常的工作中,我們往往需要給前端(WEB端、IOS、Android)或者第三方提供接口,這個(gè)時(shí)候我們就需要給他們提供一份詳細(xì)的API說(shuō)明文檔。這篇文章我們就來(lái)分享一種API文檔維護(hù)的方式,即通過(guò)Swagger來(lái)自動(dòng)生成Restuful API文檔2018-01-01
Java實(shí)現(xiàn)替換集合中的元素的方法詳解
這篇文章主要為大家詳細(xì)介紹了Java中實(shí)現(xiàn)替換集合中的元素的常見方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02
Java實(shí)現(xiàn)synchronized鎖同步機(jī)制
synchronized是java內(nèi)置的同步鎖實(shí)現(xiàn),本文就詳細(xì)的介紹一下Java實(shí)現(xiàn)synchronized鎖同步機(jī)制,具有一定的參考價(jià)值,感興趣的可以了解一下2021-11-11
解決HttpServletRequest 流數(shù)據(jù)不可重復(fù)讀的操作
這篇文章主要介紹了解決HttpServletRequest 流數(shù)據(jù)不可重復(fù)讀的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
java讀取文件和寫入文件的方式(簡(jiǎn)單實(shí)例)
下面小編就為大家?guī)?lái)一篇java讀取文件和寫入文件的方式(簡(jiǎn)單實(shí)例)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10

