常用設(shè)計模式

常用設(shè)計模式

命令模式

命令模式中的命令(command)指的是一個執(zhí)行某些特定事情的指令岂贩。

類似場景

有時候需要向某些對象發(fā)送請求匈辱,但是并不知道請求的接收 者是誰寺擂,也不知道被請求的操作是什么。
如快餐店點餐砾医,我們不需要知道廚師是誰拿撩,我們只需要把訂單交給服務(wù)員, 然后廚師長產(chǎn)出

優(yōu)缺點

請求發(fā)送者和請求接收者能夠消除彼此之間的耦合關(guān)系

小例子:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id="div" style="height: 100px;width: 100px;background-color: blue"></div>
  <button id="button1">red</button>
  <button id="button2">black</button>
  <button id="button3">yellow</button>
  <button id="undo">undo</button>
  <button id="redo">redo</button>

  <script>
    const button1 = document.getElementById('button1')
    const button2 = document.getElementById('button2')
    const button3 = document.getElementById('button3')
    const undo = document.getElementById('undo')
    const div = document.getElementById('div')


    class Command {
      constructor() {
        this.cache = []
        this.currentIndex = 0
        this.receiver = null
      }
      execute(cmd, name = 'backgroundColor') {
        this.receiver.style[name] = cmd
        this.currentIndex++
        this.cache.push(cmd)
        console.log(this.cache)
        // console.log('execute:', this.cache, this.currentIndex)
      }
      undo(name = 'backgroundColor') {
        if(this.currentIndex <= 0) return
        let oldCmd = this.cache[--this.currentIndex]
        this.receiver.style[name] = oldCmd
        console.log('undo:', this.cache, this.currentIndex)
      }
      redo(name = 'backgroundColor') {
        if (this.currentIndex >= this.cache.length - 1) return
        let preColor = this.cache[this.currentIndex + 1]
        this.currentIndex++
        this.receiver.style[name] = preColor
        console.log('redo:', this.cache, this.currentIndex)
      }
      setReceiver(target, name = 'backgroundColor') {
        this.receiver = target
        this.cache.push(this.receiver.style[name])
        console.log('setReceiver:', this.cache, this.currentIndex)
      }
    }
    const command = new Command()
    command.setReceiver(div)

    button1.onclick = function () {
      command.execute('red')
    }
    button2.onclick = function () {
      command.execute('black')
    }
    button3.onclick = function () {
      command.execute('yellow')
    }
    undo.onclick = function () {
      command.undo()
    }
    redo.onclick = function () {
      command.redo()
    }
  </script>
</body>

</html>

單例模式

只允許存在一個實例的模式

    const Instance = (function(){
        const obj;
        return function(){
            if(obj === undefined) {
                obj = new Date();
            }
            return obj;
        }
    })();
    const i = Instance();

策略模式

定義:定義一系列的算法,把它們一個個封裝起來如蚜,并且使它們可以相互替換压恒,從而避免很多if語句,曾經(jīng)學(xué)過最簡單的策略模式雛形就是使用數(shù)組的方式解決傳入數(shù)字得到對應(yīng)星期幾問題的算法错邦。

example:比如公司的年終獎是根據(jù)員工的工資和績效來考核的探赫,績效為A的人,年終獎為工資的4倍撬呢,績效為B的人伦吠,年終獎為工資的3倍,績效為C的人魂拦,年終獎為工資的2倍


 const obj = {
    "A": function(salary: number) {
        return salary * 4;
    },
    "B" : function(salary: number) {
        return salary * 3;
    },
    "C" : function(salary: number) {
        return salary * 2;
    }
};
const calculate = function(level: string, salary: number) {
    return obj[level](salary);
};

console.log(calculate('A',10000)); // 40000

代理模式

代理模式是為一個對象提供一個代用品或占位符毛仪,以便控制對它的訪問。

場景: 比如芯勘,明星都有經(jīng)紀人作為代理箱靴。如果想請明星來辦一場商業(yè)演出,只能聯(lián)系他的經(jīng)紀人荷愕。經(jīng)紀人會把商業(yè)演出的細節(jié)和報酬都談好之后衡怀,再把合同交給明星簽棍矛。

分類

保護代理:

于控制不同權(quán)限的對象對目標對象的訪問,如上面明星經(jīng)紀人的例子

虛擬代理:

把一些開銷很大的對象抛杨,延遲到真正需要它的時候才去創(chuàng)建够委。如短時間內(nèi)發(fā)起很多個http請求,我們可以用虛擬代理實現(xiàn)一定時間內(nèi)的請求統(tǒng)一發(fā)送

Tip: 函數(shù)防抖關(guān)于防抖和節(jié)流這個寫的好

防抖(debounce)

所謂防抖怖现,就是指觸發(fā)事件后在 n 秒內(nèi)函數(shù)只能執(zhí)行一次慨绳,如果在 n 秒內(nèi)又觸發(fā)了事件,則會重新計算函數(shù)執(zhí)行時間真竖。

節(jié)流(throttle)

所謂節(jié)流脐雪,就是指連續(xù)觸發(fā)事件但是在 n 秒中只執(zhí)行一次函數(shù)。節(jié)流會稀釋函數(shù)的執(zhí)行頻率恢共。

優(yōu)缺點

  1. 可以保護對象
  2. 優(yōu)化性能战秋,減少開銷很大的對象
  3. 緩存結(jié)果

惰性請求

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id="wrapper">
    <button id="1">1</button>
    <button id="2">2</button>
    <button id="3">3</button>
    <button id="4">4</button>
    <button id="5">5</button>
    <button id="6">6</button>
    <button id="7">7</button>
    <button id="8">8</button>
  </div>
</body>
<script type="text/javascript" >
  // 模擬http請求
  const synchronousFile = function (id) {
    console.log('開始同步文件,id 為: ' + id);
  };

  const inputs = document.getElementsByTagName('input')
  const wrapper = document.getElementById('wrapper')

  wrapper.onclick = function (e) {
    if (e.target.localName === 'button') {
      // synchronousFile(e.target.id)
      proxySynchronousFile(e.target.id)
    }
  }

  const proxySynchronousFile = (function () {
    let cacheIds = [],
      timeId = 0
    return function (id) {
      if (cacheIds.indexOf(id) < 0) {
        cacheIds.push(id)
      }
      clearTimeout(timeId)
      timeId = setTimeout(() => {
        synchronousFile(cacheIds.join(','))
        cacheIds = []
      }, 1000)
    }
  })()
</script>
</html>

明星報價場景


// 明星

let star = {
    name: 'cxk',
    age: 25,
    phone: '0000000000'
}

// 經(jīng)紀人
let agent = new Proxy(star, {
    get: function (target, key) {
        if (key === 'phone') {
            // 返回經(jīng)紀人自己的手機號
            return '18611112222'
        }
        if (key === 'price') {
            // 明星不報價讨韭,經(jīng)紀人報價
            return 120000
        }
        return target[key]
    },
    set: function (target, key, val) {
        if (key === 'customPrice') {
            if (val < 100000) {
                // 最低 10w
                throw new Error('價格太低')
            } else {
                target[key] = val
                return true
            }
        }
    }
})

// 主辦方
console.log(agent.name)
console.log(agent.age)
console.log(agent.phone)
console.log(agent.price)

// 想自己提供報價(砍價脂信,或者高價爭搶)
agent.customPrice = 150000
// agent.customPrice = 90000  // 報錯:價格太低
console.log('customPrice', agent.customPrice)

發(fā)布訂閱模式

如果忘記了,就去看vue源碼吧透硝,沒有寫的比它更好的了~

觀察者模式

迭代器模式

內(nèi)部迭代器函數(shù)

內(nèi)部已經(jīng)定義好了迭代規(guī)則狰闪,它完全接手整個迭代過程,外部只需要一次初始調(diào)用濒生,去原型上找這個Symbol(Symbol.iterator)判斷當(dāng)前變量或者實例是否可以迭代

這里主要指的外部迭代器函數(shù)埋泵,自定義和封裝的

loadsh each 函數(shù)


 class Iterator {
    this.list: Array<any>
    this.index: number
    constructor(conatiner: Container) {
        this.list = conatiner.list
        this.index = 0
    }
    next(): any {
        if (this.hasNext()) {
            return this.list[this.index++]
        }
        return null
    }
    hasNext(): boolean {
        if (this.index >= this.list.length) {
            return false
        }
        return true
    }
}

class Container {
    this.list: Array<any>
    constructor(list: Array<any>) {
        this.list = list
    }
    getIterator(): Iterator {
        return new Iterator(this)
    }
}
≠≠≠
// test
let container = new Container([1, 2, 3, 4, 5])
let iterator = container.getIterator()
while(iterator.hasNext()) {
    console.log(iterator.next())
}

優(yōu)缺點

優(yōu)點: 內(nèi)部迭代器在調(diào)用的時候非常方便,外界不用關(guān)心迭代器內(nèi)部的實現(xiàn)罪治,跟迭代器的交互也僅 僅是一次初始調(diào)用

缺點: 由于內(nèi)部迭代器的迭代規(guī)則已經(jīng)被提前規(guī)定丽声,默認 forEach 函數(shù)就無法同時迭代多個數(shù)組forEach(...args,()=>{})

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市觉义,隨后出現(xiàn)的幾起案子雁社,更是在濱河造成了極大的恐慌,老刑警劉巖晒骇,帶你破解...
    沈念sama閱讀 210,835評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件霉撵,死亡現(xiàn)場離奇詭異,居然都是意外死亡洪囤,警方通過查閱死者的電腦和手機徒坡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評論 2 383
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來箍鼓,“玉大人崭参,你說我怎么就攤上這事】羁В” “怎么了何暮?”我有些...
    開封第一講書人閱讀 156,481評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長铐殃。 經(jīng)常有香客問我海洼,道長,這世上最難降的妖魔是什么富腊? 我笑而不...
    開封第一講書人閱讀 56,303評論 1 282
  • 正文 為了忘掉前任坏逢,我火速辦了婚禮,結(jié)果婚禮上赘被,老公的妹妹穿的比我還像新娘是整。我一直安慰自己,他們只是感情好民假,可當(dāng)我...
    茶點故事閱讀 65,375評論 5 384
  • 文/花漫 我一把揭開白布浮入。 她就那樣靜靜地躺著,像睡著了一般羊异。 火紅的嫁衣襯著肌膚如雪事秀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,729評論 1 289
  • 那天野舶,我揣著相機與錄音易迹,去河邊找鬼。 笑死平道,一個胖子當(dāng)著我的面吹牛睹欲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播一屋,決...
    沈念sama閱讀 38,877評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼句伶,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了陆淀?” 一聲冷哼從身側(cè)響起考余,我...
    開封第一講書人閱讀 37,633評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎轧苫,沒想到半個月后楚堤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,088評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡含懊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,443評論 2 326
  • 正文 我和宋清朗相戀三年身冬,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片岔乔。...
    茶點故事閱讀 38,563評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡酥筝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出雏门,到底是詐尸還是另有隱情嘿歌,我是刑警寧澤掸掏,帶...
    沈念sama閱讀 34,251評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站宙帝,受9級特大地震影響丧凤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜步脓,卻給世界環(huán)境...
    茶點故事閱讀 39,827評論 3 312
  • 文/蒙蒙 一愿待、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧靴患,春花似錦仍侥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,712評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至相嵌,卻和暖如春腿时,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饭宾。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評論 1 264
  • 我被黑心中介騙來泰國打工批糟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人看铆。 一個月前我還...
    沈念sama閱讀 46,240評論 2 360
  • 正文 我出身青樓徽鼎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親弹惦。 傳聞我的和親對象是個殘疾皇子否淤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,435評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 抽象工廠 抽象工廠模式提供了一個接口,用于創(chuàng)建相關(guān)或依賴對象的族棠隐,而不指定具體的類石抡。 客戶與從工廠獲得的具體對象的...
    woshishui1243閱讀 3,355評論 1 5
  • 基礎(chǔ)知識 設(shè)計模式概述 從招式與內(nèi)功談起——設(shè)計模式概述(一):設(shè)計模式從何而來? 從招式與內(nèi)功談起——設(shè)計模式概...
    Java黎先生閱讀 608評論 0 7
  • I. 引言 設(shè)計模式(Design Pattern)是一套被反復(fù)使用助泽、多數(shù)人知曉的啰扛、經(jīng)過分類的、代碼設(shè)計經(jīng)驗的總結(jié)...
    garyond閱讀 2,677評論 0 2
  • 曾經(jīng)有一部科幻驚悚電影《人獸雜交》,不知道大家有沒有看過续徽,這部電影對于小編來說蚓曼,簡直就是童年陰影,在這部電影當(dāng)中講...
    2d81017dd65c閱讀 1,022評論 0 1
  • 優(yōu)才計劃 是香港政府于2006年推出的一項設(shè)有配額(1000人/年)的移民吸納計劃炸宵,旨在吸引高技術(shù)和行業(yè)優(yōu)秀人才來...
    花生草閱讀 652評論 0 0