欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

JavaScript中觀察者模式與發(fā)布訂閱模式的用法

這篇文章主要講解了JavaScript中觀察者模式與發(fā)布訂閱模式的用法,內(nèi)容清晰明了,對(duì)此有興趣的小伙伴可以學(xué)習(xí)一下,相信大家閱讀完之后會(huì)有幫助。

成都創(chuàng)新互聯(lián)公司網(wǎng)站建設(shè)公司,提供成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作,網(wǎng)頁設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);可快速的進(jìn)行網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,是專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!

學(xué)習(xí)了一段時(shí)間設(shè)計(jì)模式,當(dāng)學(xué)到觀察者模式和發(fā)布訂閱模式的時(shí)候遇到了很大的問題,這兩個(gè)模式有點(diǎn)類似,有點(diǎn)傻傻分不清楚,博客起因如此,開始對(duì)觀察者和發(fā)布訂閱開始了Google之旅。對(duì)整個(gè)學(xué)習(xí)過程做一個(gè)簡單的記錄。

觀察者模式

當(dāng)對(duì)象間存在一對(duì)多關(guān)系時(shí),則使用觀察者模式(Observer Pattern)。比如,當(dāng)一個(gè)對(duì)象被修改時(shí),則會(huì)自動(dòng)通知它的依賴對(duì)象。觀察者模式屬于行為型模式。在觀察模式中共存在兩個(gè)角色觀察者(Observer)被觀察者(Subject),然而觀察者模式在軟件設(shè)計(jì)中是一個(gè)對(duì)象,維護(hù)一個(gè)依賴列表,當(dāng)任何狀態(tài)發(fā)生改變自動(dòng)通知它們。

其實(shí)觀察者模式是一個(gè)或多個(gè)觀察者對(duì)目標(biāo)的狀態(tài)感興趣,它們通過將自己依附在目標(biāo)對(duì)象之上以便注冊(cè)所感興趣的內(nèi)容。目標(biāo)狀態(tài)發(fā)生改變并且觀察者可能對(duì)這些改變感興趣,就會(huì)發(fā)送一個(gè)通知消息,調(diào)用每個(gè)觀察者的更新方法。當(dāng)觀察者不再對(duì)目標(biāo)狀態(tài)感興趣時(shí),它們可以簡單的將自己從中分離。

在觀察者模式中一共分為這么幾個(gè)角色:

  1. Subject:維護(hù)一系列觀察者,方便添加或刪除觀察者
  2. Observer:為那些在目標(biāo)狀態(tài)發(fā)生改變時(shí)需要獲得通知的對(duì)象提供一個(gè)更新接口
  3. ConcreteSuject:狀態(tài)發(fā)生改變時(shí),想Observer發(fā)送通知,存儲(chǔ)ConcreteObserver的狀態(tài)
  4. ConcreteObserver:具體的觀察者
舉例

舉一個(gè)生活中的例子,公司老板可以為下面的工作人員分配認(rèn)為,如果老板作為被觀察者而存在,那么下面所屬的那些員工則就作為觀察者而存在,為工作人員分配的任務(wù)來通知下面的工作人員應(yīng)該去做哪些工作。

通過上面的例子可以對(duì)觀察者模式有一個(gè)簡單的認(rèn)知,接下來結(jié)合下面的這張圖來再次分析一下上面的例子。

如果Subject = 老板的話,那么Observer N = 工作人員,如果細(xì)心觀察的話會(huì)發(fā)現(xiàn)下圖中莫名到的多了一個(gè)notify(),那么上述例子中的工作就是notify()。

JavaScript中觀察者模式與發(fā)布訂閱模式的用法

既然各個(gè)關(guān)系已經(jīng)屢清楚了,下面通過代碼來實(shí)現(xiàn)一下上述的例子:

// 觀察者隊(duì)列
class ObserverList{
  constructor(){
    this.observerList = {};
  }
  Add(obj,type = "any"){
    if(!this.observerList[type]){
      this.observerList[type] = [];
    }
    this.observerList[type].push(obj);
  }
  Count(type = "any"){
    return this.observerList[type].length;
  }
  Get(index,type = "any"){
    let len = this.observerList[type].length;
    if(index > -1 && index < len){
      return this.observerList[type][index]
    }
  }
  IndexOf(obj,startIndex,type = "any"){
    let i = startIndex,
      pointer = -1;
    let len = this.observerList[type].length;
    while(i < len){
      if(this.observerList[type][i] === obj){
        pointer = i;
      }
      i++;
    }
    return pointer;
  }
  RemoveIndexAt(index,type = "any"){
    let len = this.observerList[type].length;
    if(index === 0){
      this.observerList[type].shift();
    }
    else if(index === len-1){
      this.observerList[type].pop();
    }
    else{
      this.observerList[type].splice(index,1);
    }
  }
}
// 老板
class Boos {
  constructor(){
    this.observers = new ObserverList();
  }
  AddObserverList(observer,type){
    this.observers.Add(observer,type);
  }
  RemoveObserver(oberver,type){
    let i = this.observers.IndexOf(oberver,0,type);
    (i != -1) && this.observers.RemoveIndexAt(i,type);
  }
  Notify(type){
    let oberverCont = this.observers.Count(type);
    for(let i=0;i<oberverCont;i++){
      let emp = this.observers.Get(i,type);
      emp && emp(type);
    }
  }
}
class Employees {
 constructor(name){
  this.name = name;
 }
 getName(){
  return this.name;
 }
}
class Work {
 married(name){
  console.log(`${name}上班`);
 }
 unemployment(name){
  console.log(`${name}出差`);
 }
 writing(name){
  console.log(`${name}寫作`);
 }
 writeCode(name){
  console.log(`${name}打代碼`);
 }
}
let MyBoos = new Boos();
let work = new Work();
let aaron = new Employees("Aaron");
let angie = new Employees("Angie");
let aaronName = aaron.getName();
let angieName = angie.getName();
MyBoos.AddObserverList(work.married,aaronName);
MyBoos.AddObserverList(work.writeCode,aaronName);
MyBoos.AddObserverList(work.writing,aaronName);
MyBoos.RemoveObserver(work.writing,aaronName);
MyBoos.Notify(aaronName);

MyBoos.AddObserverList(work.married,angieName);
MyBoos.AddObserverList(work.unemployment,angieName);
MyBoos.Notify(angieName);
// Aaron上班
// Aaron打代碼
// Angie上班
// Angie出差

代碼里面完全遵循了流程圖,Boos類作為被觀察者而存在,Staff作為觀察者,通過Work兩者做關(guān)聯(lián)。

如果相信的閱讀上述代碼的話可以出,其實(shí)觀察者的核心代碼就是peopleList這個(gè)對(duì)象,這個(gè)對(duì)象里面存放了N多個(gè)Array數(shù)組,通過run方法觸發(fā)觀察者的notify隊(duì)列。觀察者模式主要解決的問題就是,一個(gè)對(duì)象狀態(tài)改變給其他對(duì)象通知的問題,而且要考慮到易用和低耦合,保證高度的協(xié)作。當(dāng)我們?cè)谧龀绦蛟O(shè)計(jì)的時(shí)候,當(dāng)一個(gè)目標(biāo)對(duì)象的狀態(tài)發(fā)生改變,所有的觀察者對(duì)象都將得到通知,進(jìn)行廣播通知的時(shí)候,就可以使用觀察者模式啦。

優(yōu)點(diǎn)
  1. 觀察者和被觀察者是抽象耦合的。
  2. 建立一套觸發(fā)機(jī)制。
缺點(diǎn)
  1. 如果一個(gè)被觀察者對(duì)象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會(huì)花費(fèi)很多時(shí)間。
  2. 如果在觀察者和觀察目標(biāo)之間有循環(huán)依賴的話,觀察目標(biāo)會(huì)觸發(fā)它們之間進(jìn)行循環(huán)調(diào)用,可能導(dǎo)致系統(tǒng)崩潰。
  3. 觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道所觀察的目標(biāo)對(duì)象是怎么發(fā)生變化的,而僅僅只是知道觀察目標(biāo)發(fā)生了變化。
小結(jié)

對(duì)于觀察者模式在被觀察者中有一個(gè)用于存儲(chǔ)觀察者對(duì)象的list隊(duì)列,通過統(tǒng)一的方法觸發(fā),目標(biāo)和觀察者是基類,目標(biāo)提供維護(hù)觀察者的一系列方法,觀察者提供更新接口。具體觀察者和具體目標(biāo)繼承各自的基類,然后具體觀察者把自己注冊(cè)到具體目標(biāo)里,在具體目標(biāo)發(fā)生變化時(shí)候,調(diào)度觀察者的更新方法。

發(fā)布/訂閱模式

在發(fā)布訂閱模式上卡了很久,但是廢了好長時(shí)間沒有搞明白,也不知道自己的疑問在哪,于是就瘋狂Google不斷地翻閱找到自己的疑問,個(gè)人覺得如果想要搞明白發(fā)布訂閱模式首先要搞明白誰是發(fā)布者,誰是訂閱者。

發(fā)布訂閱:在軟件架構(gòu)中,發(fā)布-訂閱是一種消息范式,消息的發(fā)送者(稱為發(fā)布者)不會(huì)將消息直接發(fā)送給特定的接收者(稱為訂閱者)。而是將發(fā)布的消息分為不同的類別,無需了解哪些訂閱者(如果有的話)可能存在。同樣的,訂閱者可以表達(dá)對(duì)一個(gè)或多個(gè)類別的興趣,只接收感興趣的消息,無需了解哪些發(fā)布者(如果有的話)存在。-- 維基百科

看了半天沒整明白(&#10047;&#9697;&#8255;&#9697;),慚愧...于是,學(xué)習(xí)的路途不能止步,繼續(xù)...

大概很多人都和我一樣,覺得發(fā)布訂閱模式里的Publisher,就是觀察者模式里的Subject,而Subscriber,就是Observer。Publisher變化時(shí),就主動(dòng)去通知Subscriber。其實(shí)并不是。在發(fā)布訂閱模式里,發(fā)布者,并不會(huì)直接通知訂閱者,換句話說,發(fā)布者和訂閱者,彼此互不相識(shí)?;ゲ幌嘧R(shí)?那他們之間如何交流?

答案是,通過第三者,也就是在消息隊(duì)列里面,我們常說的經(jīng)紀(jì)人Broker。

發(fā)布者只需告訴Broker,我要發(fā)的消息,topicAAA,訂閱者只需告訴Broker,我要訂閱topicAAA的消息,于是,當(dāng)Broker收到發(fā)布者發(fā)過來消息,并且topicAAA時(shí),就會(huì)把消息推送給訂閱了topicAAA的訂閱者。當(dāng)然也有可能是訂閱者自己過來拉取,看具體實(shí)現(xiàn)。

也就是說,發(fā)布訂閱模式里,發(fā)布者和訂閱者,不是松耦合,而是完全解耦的。

JavaScript中觀察者模式與發(fā)布訂閱模式的用法

通過上面的描述終于有了一些眉目,再舉一個(gè)生活中的例子,就拿微信公眾號(hào)來說,每次微信公眾號(hào)推送消息并不是一下子推送給微信的所有用戶,而是選擇性的推送給那些已經(jīng)訂閱了該公眾號(hào)的人。

老規(guī)矩吧,用代碼實(shí)現(xiàn)一下:

class Utils {
 constructor(){
  this.observerList = {};
 }
 Add(obj,type = "any"){
  if(!this.observerList[type]){
   this.observerList[type] = [];
  }
  this.observerList[type].push(obj);
 }
 Count(type = "any"){
  return this.observerList[type].length;
 }
 Get(index,type = "any"){
  let len = this.observerList[type].length;
  if(index > -1 && index < len){
   return this.observerList[type][index]
  }
 }
 IndexOf(obj,startIndex,type = "any"){
  let i = startIndex,
    pointer = -1;
  let len = this.observerList[type].length;
  while(i < len){
   if(this.observerList[type][i] === obj){
    pointer = i;
   }
   i++;
  }
  return pointer;
 }
}
// 訂閱者
class Subscribe extends Utils {};
// 發(fā)布者
class Publish extends Utils {};
// 中轉(zhuǎn)站
class Broker {
 constructor(){
  this.publish = new Publish();
  this.subscribe = new Subscribe();
 }
 // 訂閱
 Subscribe(fn,key){
  this.subscribe.Add(fn,key);
 }
 // 發(fā)布
 Release(fn,key){
  this.publish.Add(fn,key);
 }
 Run(key = "any"){
  let publishList = this.publish.observerList;
  let subscribeList = this.subscribe.observerList;
  if(!publishList[key] || !subscribeList[key]) throw "No subscribers or published messages";
  let pub = publishList[key];
  let sub = subscribeList[key];
  let arr = [...pub,...sub];
  while(arr.length){
   let item = arr.shift();
   item(key);
  }
 }
}
class Employees {
 constructor(name){
  this.name = name;
 }
 getName(){
  let {name} = this;
  return name;
 }
 receivedMessage(key,name){
  console.log(`${name}收到了${key}發(fā)來的消息`);
 }
}
class Public {
 constructor(name){
  this.name = name;
 }
 getName(){
  let {name} = this;
  return name;
 }
 sendMessage(key){
  console.log(`${key}發(fā)送了一條消息`);
 }
}
let broker = new Broker();
let SundayPublic = new Public("Sunday");
let MayPublic = new Public("May");
let Angie = new Employees("Angie");
let Aaron = new Employees("Aaron");
broker.Subscribe(() => {
 Angie.receivedMessage(SundayPublic.getName(),Angie.getName());
},SundayPublic.getName());
broker.Subscribe(() => {
 Angie.receivedMessage(SundayPublic.getName(),Aaron.getName());
},SundayPublic.getName());
broker.Subscribe(() => {
 Aaron.receivedMessage(MayPublic.getName(),Aaron.getName());
},MayPublic.getName());
broker.Release(MayPublic.sendMessage,MayPublic.getName());
broker.Release(SundayPublic.sendMessage,SundayPublic.getName());
broker.Run(SundayPublic.getName());
broker.Run(MayPublic.getName());
// Sunday發(fā)送了一條消息
// Angie收到了Sunday發(fā)來的消息
// Aaron收到了Sunday發(fā)來的消息
// May發(fā)送了一條消息
// Aaron收到了May發(fā)來的消息

通過上面的輸出結(jié)果可以得出,只要訂閱過該公眾號(hào)的用戶,只要公眾號(hào)發(fā)送一條消息,所有訂閱過該條消息的用戶都是可以收到這條消息。雖然代碼有點(diǎn)多,但是確確實(shí)實(shí)能夠體現(xiàn)發(fā)布訂閱模式的魅力,很不錯(cuò)。

優(yōu)點(diǎn)
  1. 支持簡單的廣播通信,當(dāng)對(duì)象狀態(tài)發(fā)生改變時(shí),會(huì)自動(dòng)通知已經(jīng)訂閱過的對(duì)象。
  2. 發(fā)布者與訂閱者耦合性降低,發(fā)布者只管發(fā)布一條消息出去,它不關(guān)心這條消息如何被訂閱者使用,同時(shí),訂閱者只監(jiān)聽發(fā)布者的事件名,只要發(fā)布者的事件名不變,它不管發(fā)布者如何改變;同理賣家(發(fā)布者)它只需要將鞋子來貨的這件事告訴訂閱者(買家),他不管買家到底買還是不買,還是買其他賣家的。只要鞋子到貨了就通知訂閱者即可。
缺點(diǎn)
  1. 創(chuàng)建訂閱者需要消耗一定的時(shí)間和內(nèi)存。
  2. 雖然可以弱化對(duì)象之間的聯(lián)系,如果過度使用的話,反而使代碼不好理解及代碼不好維護(hù)。
小結(jié)

發(fā)布訂閱模式可以降低發(fā)布者與訂閱者之間的耦合程度,兩者之間從來不關(guān)系你是誰,你要作什么?訂閱者只需要跟隨發(fā)布者,若發(fā)布者發(fā)生變化就會(huì)通知訂閱者應(yīng)該也做出相對(duì)于的變化。發(fā)布者與訂閱者之間不存在直接通信,他們所有的一切事情都是通過中介者相互通信,它過濾所有傳入的消息并相應(yīng)地分發(fā)它們。發(fā)布訂閱模式可用于在不同系統(tǒng)組件之間傳遞消息的模式,而這些組件不知道關(guān)于彼此身份的任何信息。

觀察者模式與發(fā)布訂閱的區(qū)別

  1. Observer模式中,Observers知道Subject,同時(shí)Subject還保留了Observers的記錄。然而,在發(fā)布者/訂閱者中,發(fā)布者和訂閱者不需要彼此了解。他們只是在消息隊(duì)列或代理的幫助下進(jìn)行通信。
  2. Publisher / Subscriber模式中,組件是松散耦合的,而不是Observer模式。
  3. 觀察者模式主要以同步方式實(shí)現(xiàn),即當(dāng)某些事件發(fā)生時(shí),Subject調(diào)用其所有觀察者的適當(dāng)方法。發(fā)布者/訂閱者在大多情況下是異步方式(使用消息隊(duì)列)。
  4. 觀察者模式需要在單個(gè)應(yīng)用程序地址空間中實(shí)現(xiàn)。另一方面,發(fā)布者/訂閱者模式更像是跨應(yīng)用程序模式。

JavaScript中觀察者模式與發(fā)布訂閱模式的用法

如果以結(jié)構(gòu)來分辨模式,發(fā)布訂閱模式相比觀察者模式多了一個(gè)中間件訂閱器,所以發(fā)布訂閱模式是不同于觀察者模式的。如果以意圖來分辨模式,他們都是實(shí)現(xiàn)了對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都將得到通知,并自動(dòng)更新,那么他們就是同一種模式,發(fā)布訂閱模式是在觀察者模式的基礎(chǔ)上做的優(yōu)化升級(jí)。在觀察者模式中,觀察者需要直接訂閱目標(biāo)事件。在目標(biāo)發(fā)出內(nèi)容改變的事件后,直接接收事件并作出響應(yīng)。發(fā)布訂閱模式相比觀察者模式多了個(gè)事件通道,訂閱者和發(fā)布者不是直接關(guān)聯(lián)的。目標(biāo)和觀察者是直接聯(lián)系在一起的。觀察者把自身添加到了目標(biāo)對(duì)象中,可見和發(fā)布訂閱模式差別還是很大的。在這種模式下,目標(biāo)更像一個(gè)發(fā)布者,他讓添加進(jìn)來的所有觀察者都執(zhí)行了傳入的函數(shù),而觀察者就像一個(gè)訂閱者。雖然兩種模式都存在訂閱者和發(fā)布者(具體觀察者可認(rèn)為是訂閱者、具體目標(biāo)可認(rèn)為是發(fā)布者),但是觀察者模式是由具體目標(biāo)調(diào)度的,而發(fā)布/訂閱模式是統(tǒng)一由調(diào)度中心調(diào)的,所以觀察者模式的訂閱者與發(fā)布者之間是存在依賴的,而發(fā)布/訂閱模式則不會(huì)。

看完上述內(nèi)容,是不是對(duì)JavaScript中觀察者模式與發(fā)布訂閱模式的用法有進(jìn)一步的了解,如果還想學(xué)習(xí)更多內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

當(dāng)前名稱:JavaScript中觀察者模式與發(fā)布訂閱模式的用法
當(dāng)前URL:http://aaarwkj.com/article24/jessje.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站、電子商務(wù)、虛擬主機(jī)、用戶體驗(yàn)、品牌網(wǎng)站設(shè)計(jì)、關(guān)鍵詞優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站制作
欧美亚洲精品二区久久久| 欧美丰满熟妇视频在线| 日本福利写真在线观看| 午夜欧美激情在线视频| 亚洲av香蕉一区二区| 高清不卡av在线播放| 最近中文字幕免费手机版| 大胸妇女引诱老师在线观看| 99精品国产综合久久麻豆| 欧美日韩亚洲综合国产人| 日本高清久久一区二区三区| 欧美日韩一区二区三区666| 亚洲熟妇一区二区在线| 日韩欧美一区二区福利视频| 亚洲色图视频免费观看| 国产精品午夜福利亚洲综合网 | 亚洲欧美激情专区在线| 欧美日韩精品激情一区二区| 一区二区在线观看激情| 视频一区中文字幕在线| 欧美黄片在线免费观看视频| 99亚洲伊人久久精品影院 | 美国真人性做爰视频免费| 亚洲免费一区二区三区四区| 欧美一区二区日韩一区二区| 日本熟女视频免费观看| 丰满少妇一区二区三区在线观看 | 欧美护士激情第一欧美精品| 99精品久久久中文字幕日本| 国产午夜精品一区二区三区| 亚洲中文乱码一区二区| 久草手机福利在线观看| 激情一区二区三区视频| 不卡视频在线免费观看| 日韩欧美人妻中文字幕| 成人av免费高清在线| 日韩精品一区伦理视频| 日本黄色高清视频一区| 男女生做刺激性视频网站| 日韩 高清 一区二区| 97视频高清在线观看|