<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【速學(xué)速記】《設(shè)計(jì)模式》這樣學(xué)就對(duì)了!

          共 23778字,需瀏覽 48分鐘

           ·

          2021-04-30 18:11

          李運(yùn)通,微醫(yī)前端技術(shù)部前端工程師。最怕你一生碌碌無為,還安慰自己平凡可貴。

          設(shè)計(jì)模式解決什么痛點(diǎn)?

          它是解決特定問題的一系列套路,是前輩們的代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié),具有一定的普遍性,可以反復(fù)使用。其目的是為了提高代碼的可復(fù)用性、可讀性、可維護(hù)性
          設(shè)計(jì)模式的本質(zhì)是面向?qū)ο笤O(shè)計(jì)原則的實(shí)際運(yùn)用,是對(duì)類的封裝性、繼承性和多態(tài)性以及類的關(guān)聯(lián)關(guān)系和組合關(guān)系的充分理解。
          不要重復(fù)造輪子

          什么是面向?qū)ο缶幊?span style="display: inline-block;width: 12px;height: 12px;background-color: #fdc501;border-style: solid;border-width: 1px;border-color: #000000;border-radius: 50%;margin-left: 15px;">

          • 面向?qū)ο缶幊?/code>是一種編程范式或編程風(fēng)格。它以類或?qū)ο笞鳛榻M織代碼的基本單元,并將封裝、抽象、繼承、多態(tài)四大特性,作為代碼設(shè)計(jì)和實(shí)現(xiàn)的基石。
          • 面向?qū)ο缶幊陶Z言是支持類或?qū)ο蟮恼Z法機(jī)制,并有現(xiàn)成的語法機(jī)制,能方便的實(shí)現(xiàn)面向?qū)ο缶幊趟拇筇匦缘木幊陶Z言
          • 面向?qū)ο箝_發(fā)包括面向?qū)ο蠓治?OOA、面向?qū)ο笤O(shè)計(jì) OOD、面向?qū)ο缶幊?OOP

          10大設(shè)計(jì)原則

          1.單一職責(zé)原則 SRP

          實(shí)現(xiàn)類要職責(zé)單一:如果一段代碼塊(函數(shù) 類 模塊)負(fù)責(zé)多個(gè)功能,那么當(dāng) A 功能需求發(fā)生改變的時(shí)候改動(dòng)了代碼,就有可能導(dǎo)致 B 功能出現(xiàn)問題,所以一段代碼塊只應(yīng)該負(fù)責(zé)一個(gè)職責(zé)。

          2.開放-封閉原則 OCP

          要對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉:通過修改老代碼來實(shí)現(xiàn)新功能可能導(dǎo)致老模塊出現(xiàn) BUG,所以我們應(yīng)該通過開發(fā)新代碼塊來實(shí)現(xiàn)新功能

          3.里氏替換原則 LSP

          不要破壞繼承體系:程序中的子類應(yīng)該可以替換父類出現(xiàn)的任何地方并保持預(yù)期不變。所以子類盡量不要改變父類方法的預(yù)期行為

          4.接口隔離原則 ISP

          設(shè)計(jì)接口的時(shí)候要精簡(jiǎn)單一:當(dāng)類 A 只需要接口 B 中的部分方法時(shí),因?yàn)閷?shí)現(xiàn)接口需要實(shí)現(xiàn)其所有的方法,于是就造成了類 A 多出了部分不需要的代碼。這時(shí)應(yīng)該將 B 接口拆分,將類A需要和不需要的方法隔離開來

          5.依賴倒置原則 DIP

          面向接口編程:抽象不應(yīng)該依賴細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴于抽象。核心是面向接口編程,我們應(yīng)該依賴于抽象接口,而不是具體的接口實(shí)現(xiàn)類或具體的對(duì)象

          注意:上面的 SOLID 又稱為5大設(shè)計(jì)原則

          6.最少知識(shí)原則(迪米特原則)LOD

          降低耦合度:一個(gè)類或?qū)ο髴?yīng)該對(duì)其它對(duì)象保持最少的了解。只與直接的朋友(耦合)通信。

          7.組合/聚合復(fù)用原則 CRP

          多用組合少用繼承:盡可能通過組合已有對(duì)象(借用他們的能力)來實(shí)現(xiàn)新的功能,而不是使用繼承來獲取這些能力

          8.不要重復(fù)你自己 DRY

          功能語義重復(fù)應(yīng)該合并,代碼執(zhí)行重復(fù)應(yīng)該刪減,代碼邏輯重復(fù)但語義不同應(yīng)該保留

          9.盡量保持簡(jiǎn)單 KISS

          盡可能使用簡(jiǎn)單可讀性高的代碼實(shí)現(xiàn)功能,而不用邏輯復(fù)雜、實(shí)現(xiàn)難度高、可讀性差的方式

          10.不要過度設(shè)計(jì)你暫時(shí)用不到的邏輯 YAGNI

          不要過度優(yōu)化、不要過度預(yù)留擴(kuò)展點(diǎn)、不要設(shè)計(jì)同事看不懂的代碼。

          23種設(shè)計(jì)模式速記

          • 速記:5+7=11
            • 5種創(chuàng)建型
            • 7種結(jié)構(gòu)型
            • 11種行為型
          • 創(chuàng)建型:抽工單建原型
            • 抽象工廠、工廠、單例、建造者、原型
          • 結(jié)構(gòu)型:橋代理裝飾適配器,享元組合成門面
            • 橋接、代理、裝飾器、適配器、享元、組合、門面(外觀)
          • 行為型:觀察模板迭代的狀態(tài),命令中介解釋職責(zé)鏈,訪問策略備忘錄
            • 觀察者、模板、迭代、狀態(tài)、命令、中介者、解釋器、職責(zé)鏈、訪問者、策略、備忘錄

          創(chuàng)建型設(shè)計(jì)模式

          封裝對(duì)象創(chuàng)建過程,將對(duì)象的創(chuàng)建和使用解耦

          單例模式

          應(yīng)用場(chǎng)景

          處理資源訪問沖突、用來創(chuàng)建全局唯一類

          解決方案

          • 懶漢式:用到的時(shí)候才創(chuàng)建(場(chǎng)景:不一定需要用到、創(chuàng)建代價(jià)大、延遲加載、需要快速啟動(dòng)系統(tǒng))
          • 餓漢式:系統(tǒng)啟動(dòng)時(shí)創(chuàng)建(場(chǎng)景:必定用到、臨時(shí)創(chuàng)建影響響應(yīng)速度)
          • 多例:同一類的固定個(gè)數(shù)相同實(shí)例

          工廠模式

          應(yīng)用場(chǎng)景

          用來創(chuàng)建繼承同一父類、實(shí)現(xiàn)同一接口的子類對(duì)象,由給定的類型參數(shù)創(chuàng)建具體的對(duì)象。

          解決方案

          enum HelloType {
            A,
            B
          }

          interface Hello {
            sayHello()
          }

          class A implements Hello {
            sayHello() {
              console.log('A');
            }
          }

          class B implements Hello {
            sayHello() {
              console.log('B');
            }
          }

          class HelloFactory {
            static list = new Map<HelloType, Hello>([
              [HelloType.A, new A()],
              [HelloType.B, new B()]
            ])

            static getHello(type: HelloType) {
              return HelloFactory.list.get(type)
            }
          }

          // test
          HelloFactory.getHello(HelloType.A).sayHello()
          HelloFactory.getHello(HelloType.B).sayHello()

          抽象工廠模式

          應(yīng)用場(chǎng)景

          繼承同一父類、實(shí)現(xiàn)同一接口的子類對(duì)象,由給定的多個(gè)類型參數(shù)創(chuàng)建具體的對(duì)象。

          解決方案

          enum Type {
            A,
            B
          }

          enum Occupation {
            TEACHER,
            STUDENT
          }

          interface Hello {
            sayHello()
          }

          class TA implements Hello {
            sayHello() {
              console.log('Teacher A say hello')
            }
          }

          class TB implements Hello {
            sayHello() {
              console.log('Teacher B say hello')
            }
          }

          class SA implements Hello {
            sayHello() {
              console.log('Student A say hello')
            }
          }

          class SB implements Hello {
            sayHello() {
              console.log('Student B say hello')
            }
          }

          class AFactory {
            static list = new Map<Occupation, Hello>([
              [Occupation.TEACHER, new TA()],
              [Occupation.STUDENT, new SA()]
            ])

            static getHello(occupation: Occupation) {
              return AFactory.list.get(occupation)
            }
          }

          class BFactory {
            static list = new Map<Occupation, Hello>([
              [Occupation.TEACHER, new TB()],
              [Occupation.STUDENT, new SB()]
            ])

            static getHello(occupation: Occupation) {
              return BFactory.list.get(occupation)
            }
          }

          class HelloFactory {
            static list = new Map<Type, AFactory | BFactory>([
              [Type.A, AFactory],
              [Type.B, BFactory]
            ])

            static getType(type: Type) {
              return HelloFactory.list.get(type)
            }
          }

          // test
          HelloFactory.getType(Type.A).getHello(Occupation.TEACHER).sayHello()
          HelloFactory.getType(Type.A).getHello(Occupation.STUDENT).sayHello()
          HelloFactory.getType(Type.B).getHello(Occupation.TEACHER).sayHello()
          HelloFactory.getType(Type.B).getHello(Occupation.STUDENT).sayHello()

          建造者模式

          應(yīng)用場(chǎng)景

          • 創(chuàng)建時(shí)有很多必填參數(shù)需要驗(yàn)證
          • 創(chuàng)建時(shí)參數(shù)求值有先后順序、相互依賴
          • 創(chuàng)建有很多步驟,全部成功才能創(chuàng)建對(duì)象

          解決方案

          class Programmer {
            age: number
            username: string
            color: string
            area: string

            constructor(p) {
              this.age = p.age
              this.username = p.username
              this.color = p.color
              this.area = p.area
            }

            toString() {
              console.log(this)
            }
          }

          class Builder {
            age: number
            username: string
            color: string
            area: string

            build() {
              if (this.age && this.username && this.color && this.area) {
                return new Programmer(this)
              } else {
                throw new Error('缺少信息')
              }
            }

            setAge(age: number) {
              if (age > 18 && age < 36) {
                this.age = age
                return this
              } else {
                throw new Error('年齡不合適')
              }
            }

            setUsername(username: string) {
              if (username !== '小明') {
                this.username = username
                return this
              } else {
                throw new Error('小明不合適')
              }
            }

            setColor(color: string) {
              if (color !== 'yellow') {
                this.color = color
                return this
              } else {
                throw new Error('yellow不合適')
              }
            }

            setArea(area: string) {
              this.area = area
              return this
            }
          }

          // test
          const p = new Builder()
            .setAge(20)
            .setUsername('小紅')
            .setColor('red')
            .setArea('hz')
            .build()
            .toString()

          原型模式

          應(yīng)用場(chǎng)景

          • 原型模式是基于已有的對(duì)象克隆數(shù)據(jù),而不是修改原型鏈!
          • 創(chuàng)建對(duì)象的代價(jià)太大,而同類的不同實(shí)例對(duì)象屬性值基本一致。通過原型克隆的方式節(jié)約資源
          • 不可變對(duì)象通過淺克隆實(shí)現(xiàn)
          • 可變對(duì)象通過深克隆實(shí)現(xiàn),深克隆占用資源多
          • 同一對(duì)象不同時(shí)間版本,可以對(duì)比沒變化的淺克隆,變化的深克隆,然后新版本替換舊版本。

          結(jié)構(gòu)型設(shè)計(jì)模式

          總結(jié)了一些類或?qū)ο蠼M合在一起的經(jīng)典結(jié)構(gòu),這些經(jīng)典結(jié)構(gòu)可以解決特定應(yīng)用場(chǎng)景的問題,將類或?qū)ο蟮慕Y(jié)構(gòu)和使用解耦

          橋接模式

          應(yīng)用場(chǎng)景

          • 將抽象和實(shí)現(xiàn)解耦,讓它們可以獨(dú)立變化
          • 一個(gè)類存在多個(gè)獨(dú)立變化的維度,我們通過組合的方式,讓多個(gè)維度可以獨(dú)立進(jìn)行擴(kuò)展
          • 非常類似于組合優(yōu)于繼承原則

          解決方案

          enum MsgLevel {
            ERROR,
            WARN,
          }

          enum MsgType {
            EMAIL,
            PHONE
          }

          interface MsgContent {
            content()
          }

          class ErrorMsg implements MsgContent {
            content() {
              return 'ERROR'
            }
          }

          class WarnMsg implements MsgContent {
            content() {
              return 'WARN'
            }
          }

          interface MsgSender {
            send()
          }

          class PhoneSend implements MsgSender {
            msgContent: MsgContent

            constructor(msgContent: MsgContent) {
              this.msgContent = msgContent
            }

            send() {
              console.log(`phone send ${this.msgContent.content()}`)
            }
          }

          class EmailSend implements MsgSender {
            msgContent: MsgContent

            constructor(msgContent: MsgContent) {
              this.msgContent = msgContent
            }

            send() {
              console.log(`email send ${this.msgContent.content()}`)
            }
          }

          // test 此處還可以做成map結(jié)構(gòu)繼續(xù)優(yōu)化(略)
          new PhoneSend(new WarnMsg()).send()
          new PhoneSend(new ErrorMsg()).send()
          new EmailSend(new WarnMsg()).send()
          new EmailSend(new ErrorMsg()).send()

          代理模式

          應(yīng)用場(chǎng)景

          • 給原類添加非功能性需求,為了將代碼與原業(yè)務(wù)解耦
          • 業(yè)務(wù)系統(tǒng)的非功能性需求開發(fā):監(jiān)控、統(tǒng)計(jì)、鑒權(quán)、限流、日志、緩存

          解決方案

          • 通過繼承實(shí)現(xiàn)(不推薦)
          class User{
            login(){
              console.log('user login...')
            }
          }

          class UserProxy extends User{
            login() {
              console.log('login before')
              super.login()
              console.log('login after')
            }
          }
          • 通過接口實(shí)現(xiàn)(推薦)
          interface Login {
            login()
          }

          class User implements Login {
            login() {
              console.log('user login...')
            }
          }

          class UserProxy implements Login {
            user = new User()

            login() {
              console.log('login before')
              this.user.login()
              console.log('login after')
            }
          }

          裝飾器模式

          應(yīng)用場(chǎng)景

          • 裝飾器類是對(duì)原始功能的增強(qiáng)
          • 裝飾器類和原始類繼承同樣的父類,這樣我們可以對(duì)原始類嵌套多個(gè)裝飾器類
          • 主要解決繼承關(guān)系過于復(fù)雜的問題,通過組合來替代繼承
          • 可以通過對(duì)原始類嵌套使用多個(gè)裝飾器

          解決方案

          • 通過 AOP 實(shí)現(xiàn)
          Function.prototype.before = function (beforeFn{
            return (...arg) => {
              beforeFn(...arg);
              return this(...arg);
            }
          };
          Function.prototype.after = function (afterFn{
            return (...arg) => {
              const result = this(...arg);
              afterFn(...arg);
              return result;
            }
          };

          function ImportEvent1 {
            console.log('重要的事情說三遍 1')
          }

          function ImportEvent2 {
            console.log('重要的事情說三遍 2')
          }

          function ImportEvent3 {
            console.log('重要的事情說三遍 3')
          }

          // test
          ImportEvent2.before(ImportEvent1).after(ImportEvent3)()

          適配器模式

          應(yīng)用場(chǎng)景

          • 適配器模式用于補(bǔ)救設(shè)計(jì)上的缺陷,將不兼容的接口變得兼容
          • 封裝有缺陷的接口設(shè)計(jì)
          • 統(tǒng)一多個(gè)類的接口設(shè)計(jì)
          • 替換依賴的外部系統(tǒng)
          • 兼容老版本接口
          • 適配不同格式的數(shù)據(jù)

          解決方案

          • 原接口方法不多,類適配器和對(duì)象適配器都可以
          • 如果原類方法很多,并且和目標(biāo)接口差異小,用類適配器減少代碼量
          • 如果原類方法很多,并且和目標(biāo)接口差異大,用對(duì)象適配器,組合優(yōu)于繼承
          // 目標(biāo)接口格式
          interface ITarget {
            f1()

            f2()

            f3()
          }

          // 原有類與目標(biāo)接口不兼容
          class Origin {
            fa() {
            }

            fb() {
            }

            f3() {
            }
          }

          // 使用適配器來兼容
          class Adaptor implements ITarget {
            origin = new Origin()

            f1() {
              this.origin.fa()
            }

            f2() {
              this.origin.fb()
            }

            f3() {
              this.origin.f3()
            }
          }

          享元模式

          應(yīng)用場(chǎng)景

          • 共享的單元。復(fù)用對(duì)象,節(jié)省內(nèi)存,前提是享元對(duì)象是不可變對(duì)象(初始化之后不再改變)。

          解決方案

          • 比如網(wǎng)上象棋游戲有1000個(gè)房間,每個(gè)房間有1個(gè)棋盤,棋盤當(dāng)前狀態(tài)(棋子位置)各不相同,但棋子的大小、顏色、名字是相同且固定的,可以設(shè)計(jì)成享元

          組合模式

          應(yīng)用場(chǎng)景

          將一組對(duì)象組織成樹形結(jié)構(gòu),以表示一種“部分-整體”的層次結(jié)構(gòu)。組合模式讓客戶端可以統(tǒng)一單個(gè)對(duì)象和組合對(duì)象的處理邏輯(遞歸遍歷)

          解決方案

          abstract class FileSystemNode {
            path: string

            abstract getFilesCount()

            abstract getFilesSize()
          }

          class FileNode extends FileSystemNode {
            constructor(path) {
              super();
              this.path = path
            }

            getFilesCount() {
              return 1
            }

            getFilesSize() {
              return require(this.path).length
            }
          }

          class Directory extends FileSystemNode {
            subNodes = []

            constructor(path) {
              super();
              this.path = path
            }

            getFilesCount() {
              return this.subNodes.reduce(item => item.getCount(), 0)
            }

            getFilesSize() {
              return this.subNodes.reduce(item => item.getSize(), 0)
            }
          }

          門面(外觀)模式

          應(yīng)用場(chǎng)景

          • 將多個(gè)后端接口請(qǐng)求合并為一個(gè)(冗余接口),提高響應(yīng)速度,解決性能問題
          • 通過封裝細(xì)粒度接口,提供組合各個(gè)細(xì)粒度接口的高層次接口,來提高接口的易用性

          行為型設(shè)計(jì)模式

          總結(jié)了一些類或?qū)ο蠼换サ慕?jīng)典方式,將該行為相關(guān)的類或?qū)ο蠼怦?/code>

          觀察者模式

          應(yīng)用場(chǎng)景

          • 將觀察者與被觀察者解耦
          • 發(fā)布訂閱模式有發(fā)布訂閱調(diào)度中心(中間商),觀察者模式?jīng)]有!

          解決方案

          // 目標(biāo)對(duì)象
          class Subject {
            observerList: Observer[]

            constructor() {
              this.observerList = [];
            }

            addObserver(observer) {
              this.observerList.push(observer);
            }

            notify() {
              this.observerList.forEach((observer) => {
                observer.update();
              });
            }
          }

          // 觀察者
          class Observer {
            cb: Function

            constructor(cb: Function) {
              if (typeof cb === "function") {
                this.cb = cb;
              } else {
                throw new Error("Observer構(gòu)造器必須傳入函數(shù)類型!");
              }
            }

            update() {
              this.cb();
            }
          }


          // test
          const observerCallback = function ({
            console.log("我被通知了");
          };
          const observer = new Observer(observerCallback);
          const subject = new Subject();
          subject.addObserver(observer);
          subject.notify();

          模板模式

          應(yīng)用場(chǎng)景

          • 在一個(gè)方法里定義一個(gè)算法(業(yè)務(wù)邏輯)骨架,并將某些步驟推遲到子類中實(shí)現(xiàn)。模板方法模式可以讓子類在不改變算法整體結(jié)構(gòu)的情況下,重新定義算法中的某些步驟。
          • 復(fù)用 擴(kuò)展

          解決方案

          abstract class Drinks {
            firstStep() {
              console.log('燒開水')
            }

            abstract secondStep()

            thirdStep() {
              console.log('倒入杯子')
            }

            abstract fourthStep()

            drink() {
              this.firstStep()
              this.secondStep()
              this.thirdStep()
              this.fourthStep()
            }
          }

          class Tea extends Drinks {
            secondStep() {
              console.log('浸泡茶葉')
            }

            fourthStep() {
              console.log('加檸檬')
            }
          }

          class Coffee extends Drinks {
            secondStep() {
              console.log('沖泡咖啡')
            }

            fourthStep() {
              console.log('加糖')
            }
          }

          // test
          const tea = new Tea()
          tea.drink()
          const coffee = new Coffee()
          coffee.drink()

          策略模式

          應(yīng)用場(chǎng)景

          • 定義一族算法族,將每個(gè)算法分別封裝起來,讓他們可以相互替換。
          • 避免冗長(zhǎng)的 if-else 或 switch 分支判斷

          解決方案

          enum StrategyType {
            S,
            A,
            B
          }

          const strategyFn = {
            'S'function (salary: number{
              return salary * 4
            },
            'A'function (salary: number{
              return salary * 3
            },
            'B'function (salary: number{
              return salary * 2
            }
          }

          const calculateBonus = function (level: StrategyType, salary: number{
            return strategyFn[level](salary)
          }

          calculateBonus(StrategyType.A, 10000// 30000

          職責(zé)鏈模式

          應(yīng)用場(chǎng)景

          • 多個(gè)處理器 ABC 依次處理同一個(gè)請(qǐng)求,形成一個(gè)鏈條,當(dāng)某個(gè)處理器能處理這個(gè)請(qǐng)求,就不會(huì)繼續(xù)傳遞給后續(xù)處理器了
          • 過濾器 攔截器 處理器

          解決方案

          const order500 = function (orderType, pay, stock{
            if (orderType === 1 && pay === true) {
              console.log("500 元定金預(yù)購(gòu), 得到 100 元優(yōu)惠券");
              return true;
            } else {
              return false;
            }
          };

          const order200 = function (orderType, pay, stock{
            if (orderType === 2 && pay === true) {
              console.log("200 元定金預(yù)購(gòu), 得到 50 元優(yōu)惠券");
              return true;
            } else {
              return false;
            }
          };

          const orderCommon = function (orderType, pay, stock{
            if ((orderType === 3 || !pay) && stock > 0) {
              console.log("普通購(gòu)買, 無優(yōu)惠券");
              return true;
            } else {
              console.log("庫存不夠, 無法購(gòu)買");
              return false;
            }
          };

          class chain {
            fn: Function
            nextFn: Function

            constructor(fn: Function) {
              this.fn = fn;
              this.nextFn = null;
            }

            setNext(nextFn) {
              this.nextFn = nextFn
            }

            init(...arguments) {
              const result = this.fn(...arguments);
              if (!result && this.nextFn) {
                this.nextFn.init(...arguments);
              }
            }
          }

          const order500New = new chain(order500);
          const order200New = new chain(order200);
          const orderCommonNew = new chain(orderCommon);

          order500New.setNext(order200New);
          order200New.setNext(orderCommonNew);

          order500New.init(3true500); // 普通購(gòu)買, 無優(yōu)惠券

          狀態(tài)模式

          應(yīng)用場(chǎng)景

          • 將事物內(nèi)部的每個(gè)狀態(tài)分別封裝成類, 內(nèi)部狀態(tài)改變會(huì)產(chǎn)生不同行為

          解決方案

          class weakLight {
            light: Light

            constructor(light: Light) {
              this.light = light
            }

            press() {
              console.log('打開強(qiáng)光')
              this.light.setState(this.light.strongLight)
            }
          }

          class strongLight {
            light: Light

            constructor(light: Light) {
              this.light = light
            }

            press() {
              console.log('關(guān)燈')
              this.light.setState(this.light.offLight)
            }
          }

          class offLight {
            light: Light

            constructor(light: Light) {
              this.light = light
            }

            press() {
              console.log('打開弱光')
              this.light.setState(this.light.weakLight)
            }
          }


          class Light {
            weakLight: weakLight
            strongLight: strongLight
            offLight: offLight
            currentState: offLight | weakLight | strongLight //當(dāng)前狀態(tài): 默認(rèn)關(guān)燈狀態(tài)

            constructor() {
              this.weakLight = new weakLight(this)
              this.strongLight = new strongLight(this)
              this.offLight = new offLight(this)
              this.currentState = this.offLight
            }

            press() {
              this.currentState.press()
            }

            setState(state) {
              this.currentState = state
            }
          }

          // test
          const light = new Light()
          light.press()
          light.press()
          light.press()
          light.press()
          light.press()
          light.press()

          迭代器模式

          應(yīng)用場(chǎng)景

          • 遍歷集合對(duì)象

          訪問者模式

          應(yīng)用場(chǎng)景

          • 允許一個(gè)或多個(gè)操作應(yīng)用到一組對(duì)象上,解耦操作和對(duì)象本身

          備忘錄模式

          應(yīng)用場(chǎng)景

          • 在不違背封裝原則的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài),以便之后恢復(fù)對(duì)象為先前的狀態(tài)

          解決方案

          class Programmer {
            age: number
            username: string
            color: string
            area: string

            constructor(p) {
              this.age = p.age
              this.username = p.username
              this.color = p.color
              this.area = p.area
            }

            // 創(chuàng)建一個(gè)快照
            createSnapshot() {
              return {
                age: this.age,
                username: this.username,
                color: this.color,
                area: this.area
              }
            }

            // 通過快照恢復(fù)對(duì)象狀態(tài)
            restoreSnapshot(snapshot: Programmer) {
              this.age = snapshot.age
              this.username = snapshot.username
              this.color = snapshot.color
              this.area = snapshot.area
            }
          }

          命令模式

          應(yīng)用場(chǎng)景

          • 命令模式的主要作用和應(yīng)用場(chǎng)景,是用來控制命令的執(zhí)行,比如,異步、延遲、排隊(duì)執(zhí)行命令、撤銷重做命令、存儲(chǔ)命令、給命令記錄日志等。將命令的發(fā)起者和執(zhí)行者解耦。

          解決方案

          interface Command {
            execute()
          }

          class closeDoorCommand implements Command {
            execute() {
              console.log('close door');
            }
          }

          class openPcCommand implements Command {
            execute() {
              console.log('open pc');
            }
          }

          class openQQCommand implements Command {
            execute() {
              console.log('login qq');
            }
          }

          class CommandManager {
            commandList: Command[] = []

            addCommand(command: Command) {
              this.commandList.push(command)
            }

            execute() {
              this.commandList.forEach(command => {
                command.execute()
              })
            }
          }

          //test
          const commandManager = new CommandManager();
          commandManager.addCommand(new closeDoorCommand());
          commandManager.addCommand(new openPcCommand());
          commandManager.addCommand(new openQQCommand());
          commandManager.execute();

          解釋器模式

          應(yīng)用場(chǎng)景

          給定一個(gè)語言,定義它的文法表示,并定義一個(gè)解釋器,這個(gè)解釋器使用該標(biāo)識(shí)來解釋語言中的句子

          中介模式

          應(yīng)用場(chǎng)景

          • 中介模式的設(shè)計(jì)思想跟中間層很像,通過引入中介這個(gè)中間層,將一組對(duì)象之間的交互關(guān)系(依賴關(guān)系)轉(zhuǎn)換成一對(duì)多(星狀關(guān)系)。原本一個(gè)對(duì)象要跟n個(gè)對(duì)象交互,現(xiàn)在只需要跟一個(gè)中介對(duì)象交互,從而最小化對(duì)象間的交互關(guān)系,降低了代碼復(fù)雜度,提高了代碼的可讀性和可維護(hù)性。

          如何評(píng)價(jià)代碼的質(zhì)量?

          • 可讀性、可擴(kuò)展性、可維護(hù)性、可復(fù)用性、可測(cè)試性...
          • 高內(nèi)聚低耦合
          • 善戰(zhàn)者無赫赫之功善醫(yī)者無煌煌之名,大智若愚大巧若拙,真正的好代碼并不是用了多少厲害的技術(shù)與奇技淫巧,而是看盡人世繁華后的返璞歸真,寥寥幾筆實(shí)現(xiàn)了功能的同時(shí)卻沒有任何個(gè)人風(fēng)格的痕跡,小白都能看得懂的代碼才是好代碼。

          怎樣形成長(zhǎng)期記憶?

          • 想辦法把零散的知識(shí)點(diǎn)串聯(lián)起來記憶
            • 自頂向下形成金字塔結(jié)構(gòu)記憶
            • 編成關(guān)鍵字口訣記憶
          • 得意忘形
            • 將知識(shí)的精華枝干提取出來強(qiáng)化記憶,去粗取精
          • 學(xué)而不思則罔,思而不學(xué)則殆
            • 深度思考能將他人的知識(shí)真正轉(zhuǎn)化成自己的
          • 學(xué)而時(shí)習(xí)之,不亦說乎
            • 第一次學(xué)會(huì)只是腦海中的短時(shí)記憶,需要多次復(fù)習(xí)強(qiáng)化才能形成長(zhǎng)期記憶

          注意事項(xiàng)

          知識(shí)是死的,而代碼是活的,不要用固化的設(shè)計(jì)模式實(shí)現(xiàn)硬套在活的業(yè)務(wù)邏輯里。
          能學(xué)以致用是我們的學(xué)習(xí)目標(biāo),但是如果寫出來的代碼同組的其他人都看不懂,更加影響項(xiàng)目的可維護(hù)性和開發(fā)效率。所以我們可以少用慎用,但是我們必須掌握其思想。
          牢牢掌握設(shè)計(jì)模式,拿去面試、面試別人、組內(nèi)分享還是可以震懾群雄的,啊哈哈哈

          別忘記對(duì)我素質(zhì)三連,點(diǎn)贊、關(guān)注、評(píng)論



          最后


          • 歡迎加我微信,拉你進(jìn)技術(shù)群,長(zhǎng)期交流學(xué)習(xí)...

          • 歡迎關(guān)注「前端Q」,認(rèn)真學(xué)前端,做個(gè)專業(yè)的技術(shù)人...

          點(diǎn)個(gè)在看支持我吧


          瀏覽 53
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    麻豆porn | 大鸡巴免费在线观看 | 超碰啪啪 | 日本熟女视频 | 干视频在线 |