摘要:實(shí)際上,設(shè)計(jì)模式就是通過(guò)面向?qū)ο蟮奶匦裕瑢⑦@些角色解耦觀(guān)察者模式本質(zhì)上就是一種訂閱發(fā)布的模型,從邏輯上來(lái)說(shuō)就是一對(duì)多的依賴(lài)關(guān)系。在添加一個(gè)觀(guān)察者時(shí),把被主題被觀(guān)察者對(duì)象以構(gòu)造函數(shù)的形式給傳入了觀(guān)察者。
每個(gè)角色都對(duì)應(yīng)這一個(gè)類(lèi),比如觀(guān)察者模式,觀(guān)察者對(duì)應(yīng)著觀(guān)察者類(lèi),被觀(guān)察者對(duì)應(yīng)著被觀(guān)察者類(lèi)。實(shí)際上,設(shè)計(jì)模式就是通過(guò)面向?qū)ο蟮奶匦裕瑢⑦@些角色解耦
觀(guān)察者模式本質(zhì)上就是一種訂閱 / 發(fā)布的模型,從邏輯上來(lái)說(shuō)就是一對(duì)多的依賴(lài)關(guān)系。什么意思呢?好比是一群守衛(wèi)盯著一個(gè)囚犯,只要囚犯一有異動(dòng),守衛(wèi)就必須馬上采取行動(dòng)(也有可能是更新?tīng)顟B(tài),本質(zhì)上也是一種行動(dòng)),那么守衛(wèi)就是觀(guān)察者,囚犯就是被觀(guān)察者
在一個(gè)系統(tǒng)中,實(shí)現(xiàn)這種一對(duì)多的而且之間有一定關(guān)聯(lián)的邏輯的時(shí)候,由于需要保持他們之間的協(xié)同關(guān)系,所以最簡(jiǎn)便的方法是采用緊耦合,把這些對(duì)象綁定到一起。但是這樣一來(lái),一旦有擴(kuò)展或者修改的時(shí)候,開(kāi)發(fā)人員所面對(duì)的難度非常大,而且很容易造成Bug。那么觀(guān)察者模式就解決了這么一個(gè)問(wèn)題,在保持一系列觀(guān)察者和被觀(guān)察者對(duì)象協(xié)同工作的同時(shí),把解耦了它們
Coding抽象觀(guān)察者角色類(lèi)
public interface Observer { // 更新接口 public void update(); }
具體觀(guān)察者角色類(lèi)
public class ConcreteObserver implements Observer { // 觀(guān)察者的狀態(tài) private String observerState = "Initial"; // 觀(guān)察者初始狀態(tài),會(huì)隨著被觀(guān)察者變化而變化 private String name; // 觀(guān)察者名稱(chēng),用于標(biāo)記不同觀(guān)察者 private Subject concreteSubject; // 構(gòu)造觀(guān)察者,并傳入被主題對(duì)象,以及標(biāo)識(shí)該觀(guān)察者名稱(chēng) public ConcreteObserver(Subject concreteSubject, String name) { this.concreteSubject = concreteSubject; this.name = name; System.out.println("我是觀(guān)察者" + name +", 我的狀態(tài)是" + observerState); } // 觀(guān)察者狀態(tài)隨主題主題改變 public void update() { observerState = concreteSubject.SubjectState; System.out.println("我是觀(guān)察者" + name +", 我的狀態(tài)是" + observerState); } }
抽象主題角色類(lèi)
import java.util.List; public abstract class Subject { // 用來(lái)保存注冊(cè)的觀(guān)察者對(duì)象 Listlist = null; String SubjectState; // 注冊(cè)觀(guān)察者對(duì)象 public void attach(Observer observer){}; //刪除觀(guān)察者對(duì)象 public void detach(Observer observer){}; // 通知所有注冊(cè)的觀(guān)察者對(duì)象 public void nodifyObservers(String newState){}; }
具體主題角色類(lèi)
import java.util.ArrayList; import java.util.List; public class ConcreteSubject extends Subject { private Listlist = new ArrayList (); public String SubjectState; // 注冊(cè)觀(guān)察者對(duì)象 public void attach(Observer observer) { list.add(observer); System.out.println("Attached an observer"); } //刪除觀(guān)察者對(duì)象 public void detach(Observer observer){ list.remove(observer); } // 通知所有注冊(cè)的觀(guān)察者對(duì)象 public void nodifyObservers(String newState) { for(Observer observer : list) { observer.update(); } } }
客戶(hù)端
public class Client { public static void main(String[] args) { // 創(chuàng)建主題對(duì)象 Subject concreteSubject = new ConcreteSubject(); concreteSubject.attach(new ConcreteObserver(concreteSubject, "安倍晴明")); concreteSubject.attach(new ConcreteObserver(concreteSubject, "神樂(lè)")); concreteSubject.attach(new ConcreteObserver(concreteSubject, "源博雅")); concreteSubject.SubjectState = "結(jié)界突破!"; concreteSubject.nodifyObservers(concreteSubject.SubjectState); } }
運(yùn)行結(jié)果
我是觀(guān)察者安倍晴明, 我的狀態(tài)是Initial Attached an observer 我是觀(guān)察者神樂(lè), 我的狀態(tài)是Initial Attached an observer 我是觀(guān)察者源博雅, 我的狀態(tài)是Initial Attached an observer 我是觀(guān)察者安倍晴明, 我的狀態(tài)是結(jié)界突破! 我是觀(guān)察者神樂(lè), 我的狀態(tài)是結(jié)界突破! 我是觀(guān)察者源博雅, 我的狀態(tài)是結(jié)界突破!觀(guān)察者模式關(guān)鍵點(diǎn)
在主題(被觀(guān)察者)中,定義了一個(gè)集合用來(lái)存放觀(guān)察者,編寫(xiě)了注冊(cè)attach()和移除detach()觀(guān)察者的方法,這體現(xiàn)了一對(duì)多的關(guān)系,也提供了可以控制觀(guān)察者的方式
關(guān)鍵點(diǎn)1:每個(gè)觀(guān)察者需要被保存到主題(被觀(guān)察者)的集合中,并且被觀(guān)察者提供添加和刪除的方式
觀(guān)察者和被觀(guān)察者之間的交互活動(dòng)。在添加一個(gè)觀(guān)察者時(shí),把被主題(被觀(guān)察者)對(duì)象以構(gòu)造函數(shù)的形式給傳入了觀(guān)察者。最后主題(被觀(guān)察者)執(zhí)行nodifyObservers()方法,觸發(fā)所有觀(guān)察者的update()方法以更新?tīng)顟B(tài)
關(guān)鍵點(diǎn)2:被主題(被觀(guān)察者)把自己傳給觀(guān)察者,當(dāng)狀態(tài)改變后,通過(guò)遍歷或循環(huán)的方式逐個(gè)通知列表中的觀(guān)察者
但這里有個(gè)問(wèn)題,主題(被觀(guān)察者)是通過(guò)構(gòu)造函數(shù)參數(shù)的形式,傳給觀(guān)察者的,而觀(guān)察者對(duì)象時(shí)被attach()到主題(被觀(guān)察者)的list中
關(guān)鍵點(diǎn)3:雖然解耦了觀(guān)察者和主題(被觀(guān)察者)的依賴(lài),讓各自的變化不大影響另一方的變化,但是這種解耦并不徹底,沒(méi)有完全解除兩者之間的耦合
關(guān)鍵點(diǎn)4:在事件中,訂閱者和發(fā)布者之間是通過(guò)把事件處理程序綁定到委托,并不是把自身傳給對(duì)方。所以解決了觀(guān)察者模式中不完全解耦的問(wèn)題
委托,事件,和觀(guān)察者模式之間的關(guān)系觀(guān)察者模式,必然涉及到2委托和事件這兩種類(lèi)型
委托委托就是可把方法當(dāng)做另一個(gè)方法參數(shù)來(lái)傳遞,需要注意方法簽名。委托可以看做是方法的抽象,也就是方法的“類(lèi)”,一個(gè)委托的實(shí)例可以是一個(gè)或者多個(gè)方法。我們可以通過(guò)+=或者-=把方法綁定到委托或者從委托移除
事件事件是一種特殊的委托。首先事件也是委托,只是在聲明事件的時(shí)候,需要加上event,如果你用reflector去看一個(gè)事件,你會(huì)發(fā)現(xiàn)里面就3樣?xùn)|西,一個(gè)Add_xxxx方法,一個(gè)Remove_xxx方法,一個(gè)委托。和上面所定義主題(被觀(guān)察者)時(shí)的注冊(cè)attach()和移除detach()有些聯(lián)系
.Net事件機(jī)制實(shí)際上.Net的事件機(jī)制就是觀(guān)察者模式的一種體現(xiàn),并且是利用委托來(lái)實(shí)現(xiàn)。本質(zhì)上事件就是一種訂閱-發(fā)布模型也就是觀(guān)察者模式,這種機(jī)制中包含2個(gè)角色,一個(gè)是發(fā)布者,一個(gè)是訂閱者。發(fā)布者類(lèi)也就類(lèi)似于主題(被觀(guān)察者),發(fā)布者類(lèi)包含事件和委托定義,以及其之間的關(guān)系,發(fā)布者類(lèi)的對(duì)象調(diào)用事件通知其他訂閱者。而訂閱者類(lèi)也就類(lèi)似于觀(guān)察者,觀(guān)察者接受事件,并且提供處理的邏輯。也就是說(shuō),訂閱者對(duì)象(觀(guān)察者)中的方法會(huì)綁定到發(fā)布者(被觀(guān)察者)對(duì)象的委托中,一旦發(fā)布者(被觀(guān)察者)中事件被調(diào)用,發(fā)布者(被觀(guān)察者)就會(huì)調(diào)用委托中綁定的訂閱者(觀(guān)察者)的處理邏輯或者說(shuō)是處理程序,這就是通過(guò)觀(guān)察者模式實(shí)現(xiàn)的事件
觀(guān)察者模式問(wèn)答在普通的觀(guān)察者模式中,解耦并不徹底,那么在事件的發(fā)布訂閱模型中,解耦徹底嗎?為什么?
答案是肯定的。因?yàn)樵谑录校嗛喺吆桶l(fā)布者之間是通過(guò)把事件處理程序綁定到委托,并不是把自身傳給對(duì)方。所以解決了觀(guān)察者模式中不完全解耦的問(wèn)題
通過(guò)委托綁定方法來(lái)實(shí)現(xiàn)觀(guān)察者模式,會(huì)不會(huì)有什么隱患?
有的,通過(guò)+=去把方法綁定到委托,很容易忘記-=。如果只綁定不移除,這個(gè)方法會(huì)一直被引用。我們知道GC去回收的時(shí)候,只會(huì)處理沒(méi)有被引用的對(duì)象,只要是還被引用的對(duì)象時(shí)不會(huì)被回收掉的。所以如果在長(zhǎng)期不關(guān)閉的系統(tǒng)中(比如監(jiān)控系統(tǒng)),大量的代碼使用+=而不-=,運(yùn)行時(shí)間長(zhǎng)以后有可能會(huì)內(nèi)存溢出
事件,委托,觀(guān)察者模式之間的關(guān)系
委托是一種類(lèi)型,事件是一種特殊的委托,觀(guān)察者模式是一種設(shè)計(jì)模式,事件的機(jī)制是觀(guān)察者模式的一種實(shí)現(xiàn),其中訂閱者和發(fā)布者通過(guò)委托實(shí)現(xiàn)協(xié)同工作
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/66508.html
摘要:三內(nèi)置觀(guān)察者模式了解內(nèi)置觀(guān)察者模式包內(nèi)包含最基本的類(lèi)與接口,這和上面的接口與接口很類(lèi)似。根據(jù)具體的需求,如果內(nèi)置的觀(guān)察者模式不能滿(mǎn)設(shè)計(jì),那么我們可以像剛開(kāi)始那樣自己實(shí)現(xiàn)一套觀(guān)察者模式。參考資料設(shè)計(jì)模式 一、了解觀(guān)察者模式 1.1 什么是觀(guān)察者模式 觀(guān)察者模式定義了對(duì)象之間的一對(duì)多依賴(lài),這樣一來(lái),當(dāng)一個(gè)對(duì)象狀態(tài)改變時(shí),它的所有依賴(lài)者都會(huì)收到通知并自動(dòng)更新。 典型的問(wèn)題比如報(bào)社,只要你是他...
摘要:觀(guān)察者模式的使用場(chǎng)景比如你微博關(guān)注了一個(gè)人,那么這個(gè)人發(fā)布的微博就會(huì)推送到你這。 Java設(shè)計(jì)模式之觀(guān)察者模式 一直想寫(xiě)一篇學(xué)習(xí)觀(guān)察者模式的總結(jié)沒(méi)有契機(jī),今天學(xué)習(xí)阻塞隊(duì)列的原理時(shí)候看到在實(shí)現(xiàn)生產(chǎn)者消費(fèi)者的時(shí)候用到了通知模式,就是所謂的觀(guān)察者模式,正好順便整理一下。 1. 簡(jiǎn)介 觀(guān)察者模式定義對(duì)象間的一種一對(duì)多的依賴(lài)關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴(lài)于它的對(duì)象都得到通知并被自動(dòng)更...
摘要:為了幫助灰太狼擺脫被老婆平底鍋抽的悲劇,發(fā)起了解救灰太狼的行動(dòng),必須要知道觀(guān)察者模式。持有觀(guān)察者對(duì)象的集合。設(shè)計(jì)模式源碼下載 相信大家都有看過(guò)《喜洋洋與灰太狼》,說(shuō)的是灰太狼和羊族的斗爭(zhēng),而每次的結(jié)果都是灰太狼一飛沖天,伴隨著一句我還會(huì)回來(lái)的......。為灰太狼感到悲哀,抓不到羊,在家也被老婆平底鍋虐待。灰太狼為什么會(huì)這么背? 很簡(jiǎn)單,灰太狼本身就有暴露行蹤的屬性,羊咩咩就能知曉灰太...
摘要:觀(guān)察者模式觀(guān)察者模式也可以成為發(fā)布訂閱模式,此模式是對(duì)象之間的模式,對(duì)象之間呈現(xiàn)一種一對(duì)多的關(guān)系。其中的一是被觀(guān)察者,多是觀(guān)察者,故被觀(guān)察者不能產(chǎn)生多個(gè)對(duì)象,只能有一個(gè)對(duì)象供觀(guān)察者觀(guān)察,所以在寫(xiě)被觀(guān)察者的時(shí)候,需要使用到單例模式。 觀(guān)察者(Observer)模式 觀(guān)察者(Observer)模式 也可以成為發(fā)布訂閱模式,此模式是對(duì)象之間的模式,對(duì)象之間呈現(xiàn)一種一對(duì)多的關(guān)系。其中的一是被觀(guān)...
摘要:觀(guān)察者模式涉及的角色主題一對(duì)多中的一,持有數(shù)據(jù),當(dāng)數(shù)據(jù)更新時(shí),通知已注冊(cè)的觀(guān)察者觀(guān)察者一對(duì)多中的多,接收主題數(shù)據(jù)做出響應(yīng)舉個(gè)栗子一位媽媽主題有兩個(gè)孩子,取名為小愛(ài)和小冰觀(guān)察者。 概念 觀(guān)察者模式:定義了對(duì)象之間的一對(duì)多依賴(lài),這樣一來(lái),當(dāng)一個(gè)對(duì)象狀態(tài)改變時(shí),他的所有依賴(lài)者都會(huì)收到通知并自動(dòng)更新。 showImg(https://segmentfault.com/img/bVbf0or?w...
閱讀 2744·2021-11-19 09:40
閱讀 5293·2021-09-27 14:10
閱讀 2099·2021-09-04 16:45
閱讀 1461·2021-07-25 21:37
閱讀 2994·2019-08-30 10:57
閱讀 2980·2019-08-28 17:59
閱讀 1054·2019-08-26 13:46
閱讀 1407·2019-08-26 13:27