網(wǎng)站建站報(bào)價(jià)表什么軟件引流客源最快
觀察者模式
目錄
- 觀察者模式
- 1、什么是觀察者模式?
- 2、觀察者模式優(yōu)缺點(diǎn)及注意事項(xiàng)?
- 3、觀察者模式實(shí)現(xiàn)?
- 4、手寫線程安全的觀察者模式?
1、什么是觀察者模式?
??- 實(shí)例:現(xiàn)實(shí)生活中很多事物都是依賴存在的,一個(gè)發(fā)生變化會(huì)影響很多事物。比如油價(jià)上漲,關(guān)系很多企業(yè),很多家庭;紅綠燈發(fā)生變化時(shí),人們會(huì)停止,會(huì)前進(jìn)等。
??- 觀察者模式 (Observer Pattern) :是一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象,當(dāng)主題對(duì)象的狀態(tài)發(fā)生變化時(shí),會(huì)自動(dòng)通知所有觀察者,使得它們能夠自動(dòng)更新自己。適用于當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都需要得到通知的情況。
??- 觀察者模式具體的角色 :實(shí)現(xiàn)觀察者模式時(shí)要注意具體目標(biāo)對(duì)象和具體觀察者對(duì)象之間不能直接調(diào)用,否則將使兩者之間緊密耦合起來(lái),這違反了面向?qū)ο蟮脑O(shè)計(jì)原則。
- 抽象主題(Subject)角色:也叫抽象目標(biāo)類,它提供了一個(gè)用于保存觀察者對(duì)象的聚集類和增加、刪除觀察者對(duì)象的方法,以及通知所有觀察者的抽象方法。
- 具體主題(Concrete Subject)角色:也叫具體目標(biāo)類,它實(shí)現(xiàn)抽象目標(biāo)中的通知方法,當(dāng)具體主題的內(nèi)部狀態(tài)發(fā)生改變時(shí),通知所有注冊(cè)過(guò)的觀察者對(duì)象。繼承Subject類,在這里實(shí)現(xiàn)具體業(yè)務(wù),在具體項(xiàng)目中,該類會(huì)有很多變種。
- 抽象觀察者(Observer)角色:它是一個(gè)抽象類或接口,它包含了一個(gè)更新自己的抽象方法,當(dāng)接到具體主題的更改通知時(shí)被調(diào)用。
- 具體觀察者(Concrete Observer)角色:實(shí)現(xiàn)抽象觀察者中定義的抽象方法,以便在得到目標(biāo)的更改通知時(shí)更新自身的狀態(tài)。
2、觀察者模式優(yōu)缺點(diǎn)及注意事項(xiàng)?
- 優(yōu)點(diǎn):
??1.降低了目標(biāo)與觀察者之間的耦合關(guān)系,兩者之間是抽象耦合關(guān)系.符合依賴倒置原則
??2.目標(biāo)與觀察者之間建立了一套觸發(fā)機(jī)制
- 缺點(diǎn):
??1.目標(biāo)與觀察者之間的依賴關(guān)系并沒(méi)有完全解除,而且有可能出現(xiàn)循環(huán)引用
??2.當(dāng)觀察者對(duì)象很多時(shí),通知的發(fā)布會(huì)花費(fèi)很多時(shí)間,影響程序的效率
- 注意事項(xiàng):
??1.JDK8 中java.util.Observable 類和 java.util.Observer 接口定義了觀察者模式,后面版本舍棄了,因?yàn)樵谑褂卯惒教幚淼那闆r下,線程不安全。
??2.要注意循環(huán)調(diào)用情況,避免死鎖。
??3.可以去觀察消息隊(duì)列實(shí)現(xiàn),典型的觀察者模式實(shí)現(xiàn)。
3、觀察者模式實(shí)現(xiàn)?
模仿jdk8中 Observable 類 和 Observer接口實(shí)現(xiàn)
- 目標(biāo)類
public class Subject {private Vector<Observer> obs = new Vector<>();public void addObserver(Observer o) {if (o == null)throw new NullPointerException();if (!obs.contains(o)) {obs.add(o);}}public void deleteObserver(Observer o) {obs.remove(o);}public void notifyObservers() {for(Observer observer : this.obs) {observer.resopnse();}}
}
- 具體實(shí)現(xiàn)目標(biāo)類
public class ConcreteSubject extends Subject{// 具體實(shí)現(xiàn)public void doSomethings(){// 一些其它邏輯處理System.out.println("-----被觀察者發(fā)生了改變------");super.notifyObservers();}
}
- 觀察者類
public interface Observer {// 響應(yīng)void resopnse();
}
- 具體觀察者類
public class ConcreteObserver implements Observer{private int num;public ConcreteObserver(int num) {this.num = num;}@Overridepublic void resopnse() {System.out.println("觀察者"+num+"做出改變");}
}
- 執(zhí)行任務(wù)
public class Main {public static void main(String[] args) {
// --------------- 觀察者模式 -----------------// 先創(chuàng)建多個(gè)觀察者ConcreteSubject concreteSubject = new ConcreteSubject();for (int a = 0; a < 10; a++) {concreteSubject.addObserver(new ConcreteObserver(a+1));}concreteSubject.doSomethings();}
4、手寫線程安全的觀察者模式?
設(shè)定場(chǎng)景:手機(jī)花費(fèi)快沒(méi)錢了,運(yùn)營(yíng)商通知你要繳費(fèi)了。 這里運(yùn)營(yíng)商就是被觀察者,用戶就是觀察者,用戶的手機(jī)號(hào)就是注冊(cè)的一個(gè)過(guò)程,運(yùn)營(yíng)商通知用戶。
使用jdk中com.util.concurrent提供的線程安全的類:CountDownLatch,CountDownLatch就一個(gè)線程同步工具,它相當(dāng)于一個(gè)倒序計(jì)數(shù)器,用來(lái)協(xié)調(diào)多個(gè)線程的執(zhí)行。多個(gè)線程通過(guò)調(diào)用它們所共享的計(jì)數(shù)器CountDownLatch的countDown方法來(lái)讓計(jì)數(shù)器減1。通過(guò)await方法來(lái)阻塞當(dāng)前線程,直到計(jì)數(shù)器變成0。達(dá)到線程阻塞直至其他線程執(zhí)行完成被重新喚醒。主要有三個(gè)方法:
1.構(gòu)造函數(shù),初始化state的值,state等于同步線程數(shù)
2.await(),讓線程阻塞
3.countDown(),計(jì)數(shù)器(state)減1的方法。
public class Main {public static void main(String[] args) {// --------------- 安全的觀察者模式 --------------// 設(shè)定場(chǎng)景:手機(jī)花費(fèi)快沒(méi)錢了,運(yùn)營(yíng)商通知你要繳費(fèi)了。 這里運(yùn)營(yíng)商就是被觀察者,用戶就是觀察者,用戶的手機(jī)號(hào)就是注冊(cè)的一個(gè)過(guò)程,運(yùn)營(yíng)商通知用戶。ConcreteTelecomOperator telecomOperator = new ConcreteTelecomOperator("中國(guó)電信");telecomOperator.addUser(new ConcreteUser("張三"));telecomOperator.addUser(new ConcreteUser("李四"));telecomOperator.addUser(new ConcreteUser("王五"));telecomOperator.addUser(new ConcreteUser("小明"));telecomOperator.doSomeThing("通知您,您已欠費(fèi)請(qǐng)及時(shí)繳費(fèi)。祝你生活愉快!");}
}
/*** @program: practice_tools* @description: 運(yùn)營(yíng)商目標(biāo)類* @author: tiezhu* @create: 2025-01-20 09:58**/
public class TelecomOperator {private String name;private ConcurrentMap<String, User> obs;public TelecomOperator(String name) {this.name = name;obs = new ConcurrentHashMap<>();}public void addUser(User u){if (u == null)throw new NullPointerException();if (!obs.containsKey(u.getName())) {obs.put(u.getName(),u);}}public void removeUser(User u){obs.remove(u.getName());}public void notifyObservers(String content) {try {long beginTime = System.currentTimeMillis();CountDownLatch latch = new CountDownLatch(obs.size());for (User user : obs.values()) {user.response(content);latch.countDown();}latch.await();long endTime = System.currentTimeMillis();System.out.println(name + "消息發(fā)送完畢,耗時(shí):" + (endTime - beginTime));System.out.println();} catch (InterruptedException e) {e.printStackTrace();}}
}
/*** @program: practice_tools* @description: 具體目標(biāo)類* @author: tiezhu* @create: 2025-01-20 11:43**/
public class ConcreteTelecomOperator extends TelecomOperator{public ConcreteTelecomOperator(String name) {super(name);}public void doSomeThing(String content){System.out.println("開始發(fā)布信息:");super.notifyObservers(content);}
}
/*** 用戶觀察者*/
public interface User {void response(String content);String getName();
}
/*** @program: practice_tools* @description: 觀察者實(shí)體類* @author: tiezhu* @create: 2025-01-20 10:04**/
public class ConcreteUser implements User{private String name;public ConcreteUser(String name) {this.name = name;}@Overridepublic void response(String content) {System.out.println("接收到了消息為:"+content);System.out.println(name + "準(zhǔn)備去繳費(fèi)了");}@Overridepublic String getName() {return name;}
}
結(jié)果:執(zhí)行結(jié)果和創(chuàng)建順序不同,不用按照創(chuàng)建順序執(zhí)行完再執(zhí)行了。