国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

速通 JavaScript 代理模式和發布訂閱模式

開發 前端
發布訂閱模式的優點非常明顯,一為時間上的解耦,二為對象之間的解耦,但如果過度使用的話,對象和對象之間的必要聯系也將被深埋在背后,會導致程序難以跟蹤維護和理解。

1. 前言

JavaScript 是一門動態語言,在實現設計模式的時候,往往會比 Java 等靜態語言更簡便,本文將介紹在 JavaScript 中如何實現代理模式和發布訂閱模式。

2. 代理模式

2.1. 定義

在介紹定義時還是以類圖為主,雖然 JavaScript 實現設計模式時可能不會使用到類,但是類圖提供了一種通用的設計模式實現思想。

代理模式定義:為其他對象提供一種代理以控制對這個對象的訪問。

其類圖如下:

圖片圖片

類圖中的三個角色:

  • Subject 抽象主題角色:定義了具體主題和代理主題的共同接口,這樣在任何使用具體主題的地方都可以使用代理主題。
  • RealSubject 具體主題角色:邏輯的具體執行者。
  • Proxy 代理主題角色:實現了抽象主題接口,并持有對具體主題的引用。

2.2. 實現

在 JavaScript 中,你可以使用 Proxy 輕松實現代理模式,比如可以通過代理模式實現一個只接收 number 類型值的數組。

const arr = []
const numArr = new Proxy(arr, {
  set(target, key, value, proxy) {
    if (typeof value !== 'number') {
      throw Error("屬性只能是 number 類型");
    }
    return Reflect.set(target, key, value, proxy);
  }
})
numArr.push(0)
numArr.push('1') // Uncaught Error: 屬性只能是 number 類型
console.log(numArr) // Proxy(Array) {0: 0}

利用 Proxy,你還可以實現響應式編程。

const data = { userName: '' }

const render = (info) => {
  console.log(info)
  // 根據數據渲染界面
}

const proxyData = new Proxy(data, {
  set(target, key, value, receiver) {
    // 設置值
    Reflect.set(target, key, value, receiver)
    // 重新觸發渲染
    render(target)
  }
})

data.userName = 'xiaoming'// 控制臺輸出 { userName: 'xiaoming' }

當然你也可以利用 Proxy 來實現日志功能,用于跟蹤函數調用情況。

function add(a, b) {
  return a + b;
}

// 日志記錄函數
function log(message) {
  console.log(message);
}

// 創建代理對象
const proxy = newProxy(add, {
// 攔截函數調用
  apply(target, thisArg, args) {
    const result = Reflect.apply(target, thisArg, args);
    log(`函數 ${target.name} 被調用,參數: [${args.join(', ')}],返回值: ${result}`);
    return result;
  }
});

const sum1 = proxy(1, 2);  // 輸出: 函數 add 被調用,參數: [1, 2],返回值: 3
const sum2 = proxy(3, 4);  // 輸出: 函數 add 被調用,參數: [3, 4],返回值: 7

2.3. 小結

最后提一下代理模式和裝飾模式的異同點,兩者的共同點是代理類或裝飾類和原本類都具有相同的接口,不同點則是代理模式著重對代理過程的控制,而裝飾模式則是對類的功能進行加強或減弱。

3. 發布訂閱模式

3.1. 定義

發布訂閱模式的定義:定義對象間一種一對多的依賴關系,使得每當一個對象改變狀態,則所有依賴于它的對象都會得到通知并被自動更新。

其類圖如下:

圖片圖片

發布訂閱模式經常會和觀察者模式做對比,兩個設計模式廣義上設計理念是一致的,在實現上有些差別,本文更注重實際應用,故不展開此內容,借用一張圖來說明。

圖片圖片

3.2. 實現

接著來完成發布訂閱模式的簡單實現,主要是實現 subscribe 和 publish 方法。

const event = { 
  listeners: [],  // 所有訂閱者集合
  // 訂閱函數
  subscribe: function(fn) { 
    this.listeners.push(fn)
  },
  // 發布函數
  publish: function() {
    for(let i = 0; i < this.listeners.length; i++) { 
      this.listeners[i]()
    } 
  },
  // 移除訂閱函數
  unsubcribe: function(fn) { 
    const fns = this.listeners;
    // 倒序訪問方便使用 splice 移除訂閱函數
    for (let l = fns.length - 1; l >=0; l--) {
      const _fn = fns[l]; 
      if (_fn === fn){ 
        fns.splice(l, 1);
      } 
    } 
  }
}

const fn1 = () => { console.log('trigger1') }
const fn2 = () => { console.log('trigger2') }
event.subscribe(fn1)
event.subscribe(fn2)
event.publish() // 控制臺打印 trigger1, trigger2
event.unsubcribe(fn1)
event.publish() // 控制臺打印 trigger2

到此我們實現了一個簡單版本的發布訂閱。

接下來我們基于發布訂閱模式,在 React 中實現一個類似 Zustand 的狀態管理功能。

首先我們需要了解一個 React 官方 Hook useSyncExternalStore,這個 Hook 可以讓你訂閱一個外部數據源,當其中數據發生變化時,React 會觸發重新渲染。

const snapshot = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)

可以看到該 Hook 參數有三個,這里我們主要關注前兩個,第一個參數即訂閱函數,第二個參數為獲取數據源的函數,第三個和服務端渲染相關。

接下來我們要結合發布訂閱模式和 useSyncExternalStore 實現一個簡單版本的 Zustand。

const createImpl = (createState) => {
  // 相比發布訂閱模式,多了個狀態值
  let state
  let initialState
  const listeners = newSet()

  // 類似發布訂閱模式中的 publish 方法,最終會觸發訂閱者
  const setState = (nextState) => {    
    // 對比狀態值是否有變化
    if (!Object.is(nextState, state)) {
      const previousState = state
      state = Object.assign({}, state, nextState)
      // 觸發訂閱函數
      listeners.forEach((listener) => listener(state, previousState))
    }
  }

  const getState = () => state

  const getInitialState = () => initialState

  const subscribe = (listener) => {
    listeners.add(listener)
    // 返回一個取消訂閱的方法
    return() => {
      listeners.delete(listener)
    }
  }

  // 清空訂閱
  const destory = () => listeners.clear()

  const api = {
    setState,
    getState,
    getInitialState,
    subscribe,
    destory
  }

  // 調用 createState 方法返回初始狀態值,createState 參數為 set、get 和 api 對象
  initialState = (state = createState(setState, getState, api))

  return api
}

const create = (createState) => {
  const api = createImpl(createState)
  // 傳入訂閱方法和獲取數據方法到 useSyncExternalStore
  const useStore = () => useSyncExternalStore(api.subscribe, api.getState)
  // 把 api 合并到 Hook 上
  Object.assign(useStore, api)
  return useStore
}

exportdefault create

先來看下 createImpl 函數,相比于我們實現的簡單版發布訂閱模式,createImpl 內部多維護了一個狀態值,在調用發布方法(setState)時,會更新狀態值,并觸發訂閱函數,訂閱函數入參為新舊狀態值。

最后我們看下如何使用自己的狀態管理功能。

// create 方法接收一個函數參數,內部會調用函數初始化狀態值,最終返回一個 Hook
const useStore = create((set) => ({
  num: 1,
  // 通過 set 方法更新狀態值,更新后觸發所有訂閱函數的調用
  random: () =>set({ num: Math.round(Math.random() * 1000) }),
}))

function Counter() {
  // 調用 useStore,useStore 會調用 React useSyncExternalStore
  const { num, random } = useStore();
  return (
    <div>
      <p>{`Number: ${num}`}</p>
      <button onClick={random}>Random</button>
    </div>
  )
}

create 方法接收一個函數參數,用于初始化狀態,最終 create 會返回一個 Hook。在狀態值中, random 方法會調用發布方法(setState)觸發更新,因為 useSyncExternalStore 會使用第一個參數完成訂閱動作,所以此時它能接收到數據更新,隨后便返回最新的狀態值,并觸發重新渲染。

在線代碼示例:https://stackblitz.com/edit/react-9nvjhwhx?file=demo.tsx

至此我們實現了一個簡單版本 Zustand。

3.3. 小結

發布訂閱模式的優點非常明顯,一為時間上的解耦,二為對象之間的解耦,但如果過度使用的話,對象和對象之間的必要聯系也將被深埋在背后,會導致程序難以跟蹤維護和理解。

3. 總結

設計模式大體思想是要把系統中不變和變化的部分分開,封裝不變的部分,根據業務靈活替換變化的部分,這樣就可以保證系統的健壯性和可拓展性。同時在實現設計模式的同時,你通常也會很好的遵守了設計模式原則,如單一職責、依賴倒置、開閉原則、迪米特原則等。

責任編輯:武曉燕 來源: 栗子前端
相關推薦

2012-02-29 09:41:14

JavaScript

2023-11-10 09:22:06

2022-06-27 13:56:10

設計模式緩存分布式系統

2022-12-02 07:28:58

Event訂閱模式Spring

2009-11-05 10:07:37

WCF設計模式

2021-09-08 07:18:30

代理模式對象

2012-01-13 15:59:07

2021-06-29 08:54:23

設計模式代理模式遠程代理

2010-03-25 08:52:30

PHP設計模式代理模式

2011-04-06 11:41:25

Java動態代理

2024-02-26 11:52:38

代理模式設計

2022-11-30 17:05:33

代碼程序場景

2021-08-02 17:21:08

設計模式訂閱

2024-07-29 08:34:18

C++訂閱者模式線程

2024-04-10 12:27:43

Python設計模式開發

2015-09-08 13:39:10

JavaScript設計模式

2022-09-07 08:25:08

代理模式設計模式代碼

2023-12-04 08:24:23

2023-11-02 21:11:11

JavaScript設計模式

2011-03-23 10:40:51

java代理模式
點贊
收藏

51CTO技術棧公眾號

99在线免费视频| 色999日韩自偷自拍美女| 午夜精品视频在线观看| 91久色国产| 白嫩亚洲一区二区三区| 欧美三级在线视频| www.99色.com| 国产乱色国产精品免费视频| 91亚洲永久免费精品| 视频二区欧美| 精品一区电影国产| 秋霞影院午夜丰满少妇在线视频| 国产精品伦一区二区三级视频| 亚洲一区不卡在线| 欧美成人日韩| 黑人精品xxx一区| 日韩中文字幕三区| 久久国产一二区| 色网综合在线观看| 亚洲制服国产| 国产校园另类小说区| 中文字幕日韩在线观看| 国产原创欧美精品| 欧美xxxx黑人又粗又长| 国产午夜一区二区三区| 亚洲激情一区二区三区| √8天堂资源地址中文在线| 欧美专区一区二区三区| 国产精品海角社区在线观看| 精品欧美一区二区三区在线观看| 国产精品高清乱码在线观看| 日韩成人精品一区| 欧美日韩国产第一页| 成人国产精品入口免费视频| 日韩成人在线视频网站| 国产丝袜精品丝袜| 精品国产电影一区二区| 成人ww免费完整版在线观看| 美国一区二区三区在线播放| 99视频免费观看| 久久久9色精品国产一区二区三区| 欧美一级视频一区二区| 国产成人aa在线观看网站站| 久久亚洲欧美日韩精品专区| 视频在线日韩| xxxxx成人.com| 精品一级视频| 欧美激情精品久久久久久大尺度| av一级亚洲| 欧美视频自拍偷拍| h视频在线播放| 欧美精品视频www在线观看| 免费的av在线| 国产99久久久国产精品潘金| 天天夜碰日日摸日日澡性色av| jiyouzz国产精品久久| 777米奇影视第四色| 影音先锋日韩在线| 亚洲一区亚洲二区亚洲三区| 国内精品美女在线观看| 中文字幕日韩专区| 黄色成人小视频| 亚洲高清在线视频| 日本一区视频在线| 国内精品麻豆美女在线播放视频| 久久久久国产精品一区| 成人免费在线| 欧美精品一区二区在线播放| 裤袜国产欧美精品一区| 久热精品视频在线观看一区| 欧美猛男同性videos| 91精品网站| 国产一区二区三区蝌蚪| 91免费精品国偷自产在线| 欧美三级午夜理伦三级中文幕| 国产午夜精品视频| 污视频在线观看免费| 在线中文字幕一区| 中文字幕有码av| 香蕉av福利精品导航| 永久免费av在线| 亚洲视频自拍偷拍| 欧美禁忌电影网| 日韩欧美视频第二区| 久久精品视频一区二区| 国产中文字幕在线看| 亚洲开心激情网| 蜜桃a∨噜噜一区二区三区| 狠狠色综合色区| 95精品视频在线| 欧洲免费在线视频| 中文字幕在线亚洲| 欧美 日韩 国产 一区| 免费在线观看污污视频| 国产精品毛片一区二区在线看| 国产欧美韩日| 99久久精品国产一区二区三区 | 国产91在线观看| 可以免费看污视频的网站| 久久97超碰色| 97人摸人人澡人人人超一碰| 久久国产三级精品| 免费黄视频网站| 国产精品女主播av| 2017亚洲天堂1024| 色与欲影视天天看综合网| 国产日韩1区| av在线dvd| 国产精品久久久久久久久久免费看| 在线观看欧美激情| 国产精品福利影院| www中文字幕在线观看| 国产极品精品在线观看| 国产一区二区网址| 色综合成人av| 欧美国产日本高清在线 | 在线观看一区二区视频| 国产成人免费视频网站视频社区| 国产伦精品一区二区三区照片 | 欧美电影免费看| 欧美精品一区二区精品网| 免费成人高清在线视频theav| 日本不卡一区| 日韩欧美精品中文字幕| 一区二区成人| 欧美日韩不卡合集视频| 麻豆国产精品一区二区三区| 韩国福利在线| 日本免费在线精品| www.亚洲激情.com| 成人片在线看| 不卡一区二区三区视频| 亚洲美女免费视频| 中文在线www| 精品人伦一区二区三区蜜桃免费| 外国成人毛片| 不卡中文字幕av| 蜜乳av一区二区三区| 阿v免费在线观看| 国产精品久久久久久久久久尿| www国产精品av| 欧美一级大片| 日本黑人久久| 欧美日韩成人激情| 芒果视频成人app| 日韩在线观看电影完整版高清免费| 欧美日韩免费网站| 亚洲人挤奶视频| 国产精品美女诱惑| 亚洲成人综合视频| 一区二区三区日本久久久| 色乱码一区二区三区在线| 精品久久久免费| 国产欧美日韩免费观看| 免费羞羞视频| 日本精品视频在线| 亚洲图片激情小说| 久久精品色综合| 国产理论片免费观看| 欧美在线亚洲一区| 亚洲午夜一二三区视频| 国产精品久久久久久影院8一贰佰 国产精品久久久久久麻豆一区软件 | 久久精品电影一区二区| 国产一区二区三区精品视频| 神马久久午夜| www久久久久| 久久亚洲美女| 欧美热在线视频精品999| 高清一区二区中文字幕| 欧美人体一区二区三区| 欧美成人性生活视频| 成人免费看黄网址| koreanbj精品视频一区| 国产精品羞羞答答xxdd | 美女视频免费一区| 色综合视频一区二区三区44| av免费播放| 天天干夜夜干| 精品精品国产高清a毛片牛牛 | 国产精品视频一区二区三区综合| 97超碰资源站在线观看| 亚洲国产精品久久久久秋霞不卡| 免费视频一区| 91超碰在线免费| 国产毛片久久久久久国产毛片| 亚洲啊v在线观看| 高清毛片在线看| 久久中文字幕在线| 国产人成一区二区三区影院| 自拍偷拍精品| 成人av一区| 中文字幕在线观看一区二区三区| 国产午夜精品视频| 亚洲四区在线观看| 激情欧美日韩一区| 91成人在线| 精品一二三四| 欧美丰满少妇xxxx| 亚洲一区二区三区在线播放| 免费在线欧美黄色|