[封裝01-設(shè)計(jì)模式] 設(shè)計(jì)原則 和 工廠模式(簡(jiǎn)單抽象方法) 適配器模式 裝飾器模式

design_principle設(shè)計(jì)原則.png
Error.png

導(dǎo)航

[react] Hooks

[封裝-設(shè)計(jì)模式01] 設(shè)計(jì)原則 和 工廠模式(簡(jiǎn)單抽象方法) 適配器模式 裝飾器模式

[React 從零實(shí)踐01-后臺(tái)] 代碼分割
[React 從零實(shí)踐02-后臺(tái)] 權(quán)限控制
[React 從零實(shí)踐03-后臺(tái)] 自定義hooks
[React 從零實(shí)踐04-后臺(tái)] docker-compose 部署react+egg+nginx+mysql
[React 從零實(shí)踐05-后臺(tái)] Gitlab-CI使用Docker自動(dòng)化部署

[源碼-webpack01-前置知識(shí)] AST抽象語(yǔ)法樹(shù)
[源碼-webpack02-前置知識(shí)] Tapable
[源碼-webpack03] 手寫(xiě)webpack - compiler簡(jiǎn)單編譯流程
[源碼] Redux React-Redux01
[源碼] axios
[源碼] vuex
[源碼-vue01] data響應(yīng)式 和 初始化渲染
[源碼-vue02] computed 響應(yīng)式 - 初始化,訪問(wèn),更新過(guò)程
[源碼-vue03] watch 偵聽(tīng)屬性 - 初始化和更新
[源碼-vue04] Vue.set 和 vm.$set
[源碼-vue05] Vue.extend

[源碼-vue06] Vue.nextTick 和 vm.$nextTick
[部署01] Nginx
[部署02] Docker 部署vue項(xiàng)目
[部署03] gitlab-CI

[數(shù)據(jù)結(jié)構(gòu)和算法01] 二分查找和排序

[深入01] 執(zhí)行上下文
[深入02] 原型鏈
[深入03] 繼承
[深入04] 事件循環(huán)
[深入05] 柯里化 偏函數(shù) 函數(shù)記憶
[深入06] 隱式轉(zhuǎn)換 和 運(yùn)算符
[深入07] 瀏覽器緩存機(jī)制(http緩存機(jī)制)
[深入08] 前端安全
[深入09] 深淺拷貝
[深入10] Debounce Throttle
[深入11] 前端路由
[深入12] 前端模塊化
[深入13] 觀察者模式 發(fā)布訂閱模式 雙向數(shù)據(jù)綁定
[深入14] canvas
[深入15] webSocket
[深入16] webpack
[深入17] http 和 https
[深入18] CSS-interview
[深入19] 手寫(xiě)Promise
[深入20] 手寫(xiě)函數(shù)
[深入21] 數(shù)據(jù)結(jié)構(gòu)和算法 - 二分查找和排序
[深入22] js和v8垃圾回收機(jī)制
[深入23] JS設(shè)計(jì)模式 - 代理叉瘩,策略艘虎,單例

[前端學(xué)java01-SpringBoot實(shí)戰(zhàn)] 環(huán)境配置和HelloWorld服務(wù)
[前端學(xué)java02-SpringBoot實(shí)戰(zhàn)] mybatis + mysql 實(shí)現(xiàn)歌曲增刪改查
[前端學(xué)java03-SpringBoot實(shí)戰(zhàn)] lombok络它,日志诉瓦,部署
[前端學(xué)java04-SpringBoot實(shí)戰(zhàn)] 靜態(tài)資源 + 攔截器 + 前后端文件上傳
[前端學(xué)java05-SpringBoot實(shí)戰(zhàn)] 常用注解 + redis實(shí)現(xiàn)統(tǒng)計(jì)功能
[前端學(xué)java06-SpringBoot實(shí)戰(zhàn)] 注入 + Swagger2 3.0 + 單元測(cè)試JUnit5
[前端學(xué)java07-SpringBoot實(shí)戰(zhàn)] IOC掃描器 + 事務(wù) + Jackson

(一) 前置知識(shí)

(1) 一些單詞

principle 原則 原理
responsibility 職責(zé) 責(zé)任
substitution 代替 置換
// Single Responsibility Principle 單一職責(zé)原則

abstract 抽象的
simple 簡(jiǎn)單的
show up 出現(xiàn),露面

advanced 高級(jí)的殿怜,先進(jìn)的
configuration 配置
// advanced configuration 高級(jí)配置

constraint 約束
peek 偷看
shape 形狀
anonymous 匿名的

(2) Error

  • new Error(message)
  • 拋出Error實(shí)例對(duì)象后,整個(gè)程序就中斷在錯(cuò)誤發(fā)生的地方曙砂,不再往下執(zhí)行
  • error實(shí)例屬性
    • message 錯(cuò)誤提示信息
    • name 錯(cuò)誤名稱(chēng) ( 非標(biāo)準(zhǔn)屬性 )
    • stack 錯(cuò)誤堆棧 ( 非標(biāo)準(zhǔn)屬性 )
  • 六種錯(cuò)誤對(duì)象
    • SyntaxError 語(yǔ)法錯(cuò)誤
    • ReferenceError ( 引用一個(gè)不存在的變量時(shí)發(fā)生的錯(cuò)誤 ) 或者 ( 將一個(gè)值分配給無(wú)法分配的對(duì)象 )
    • RangeError 一個(gè)值超出有效范圍時(shí)發(fā)生的錯(cuò)誤
    • TypeError ( 變量或者參數(shù) ) 不是 ( 預(yù)期類(lèi)型 ) 時(shí)候發(fā)生的錯(cuò)誤
    • RUIError URI 相關(guān)函數(shù)的參數(shù)不正確時(shí)拋出的錯(cuò)誤
    • EvalError eval函數(shù)沒(méi)有被正確執(zhí)行時(shí)拋出的錯(cuò)誤
  • 第七種头谜,是自定義錯(cuò)誤對(duì)象
    • 原理
      • 1.就是普通的構(gòu)造函數(shù)(具有name,message麦轰,stack等屬性)
      • 2.將構(gòu)造函數(shù)的prototype屬性指向 new Error() 生成的實(shí)例
      • 3.將構(gòu)造函數(shù)的prototype.contructor屬性指向構(gòu)造函數(shù)自己乔夯,防止引用出錯(cuò)
  • throw語(yǔ)句
    • throw語(yǔ)句的作用是:手動(dòng)中斷程序執(zhí)行,并拋出錯(cuò)誤款侵,即手動(dòng)拋出錯(cuò)誤
    • 注意:throw可以?huà)伋鋈我忸?lèi)型的值末荐,不一定是錯(cuò)誤實(shí)例
    try {
          // throw new Error('錯(cuò)誤了')
          // ---------------------------- 注意:throw 可以?huà)伋鋈魏晤?lèi)型的值,不局限于錯(cuò)誤對(duì)象實(shí)例
          throw '錯(cuò)誤了2'
    } catch(e) {
          // console.log(e.message) ----- 注意:這里對(duì)應(yīng)的是try拋出的錯(cuò)誤對(duì)象新锈,錯(cuò)誤對(duì)象具有message屬性
          // ---------------------------- 注意:catch() 的參數(shù)是try代碼塊中拋出的值甲脏,即也可以是任意類(lèi)型
          console.log(e);
    }
    
  • try...catch(e)結(jié)構(gòu)
    • try...catch主要作用:是對(duì)錯(cuò)誤進(jìn)行處理,選擇是否往下執(zhí)行
    • catch(e) 接受的參數(shù)表示try代碼塊拋出的值妹笆,任意類(lèi)型块请,因?yàn)閠hrow可以?huà)伋鋈我忸?lèi)型
    • 注意:catch捕獲錯(cuò)誤后,程序不會(huì)中斷拳缠,會(huì)按正常流程繼續(xù)執(zhí)行下去
      try {
        throw "出錯(cuò)了";
      } catch (e) {
        console.log(111);
      }
      console.log(222);
      // 111
      // 222 還是會(huì)正常執(zhí)行
    
    • try...catch還可以嵌套try...catch
  • try...finally結(jié)構(gòu)
    • try...catch結(jié)構(gòu)允許在最后添加一個(gè)finally代碼塊墩新,表示不管是否出現(xiàn)錯(cuò)誤,都必需在最后運(yùn)行的語(yǔ)句
    • 如果在try...catch中有return語(yǔ)句窟坐,會(huì)在finally執(zhí)行完畢后才會(huì)去執(zhí)行return后面的語(yǔ)句
Error.png

(二) 六大設(shè)計(jì)原則

  • 單一職責(zé)原則 Single Responsibility Principle
  • 開(kāi)放封閉原則 Open Closed Principle
  • 里氏替換原則 Liskov Substitution Principle
  • 迪米特法則(最少知識(shí)原則) Law of Demeter
  • 接口隔離原則 Interface Segregation Principle
  • 依賴(lài)倒置原則 Dependence Inversion Principle

(2.1) 單一職責(zé)原則

  • 關(guān)鍵詞
    • ( 單一 ) ( 職責(zé) )
    • 如果我們有兩個(gè)動(dòng)機(jī)去改寫(xiě)一個(gè)方法海渊,那么這個(gè)方法就具有兩個(gè)職責(zé)
  • 單一職責(zé)原則
    • 一個(gè)方法只做一件事
    • 這樣需求變遷,則只會(huì)影響到最小粒度的方法哲鸳,其他方法不會(huì)受到影響
  • 如何劃分職責(zé)???
    • 兩個(gè)完全不一樣的功能臣疑,不應(yīng)放在一個(gè)類(lèi)中
    • 一個(gè)類(lèi)中應(yīng)該是 ( 一組相關(guān)性很高的函數(shù),或者數(shù)據(jù)的封裝 )
    • 如果隨著需求的變化徙菠,有兩個(gè)職責(zé)總是同時(shí)變化讯沈,那就不必分離他們
    • 即使兩個(gè)職責(zé)已經(jīng)被耦合在一起,但它們還沒(méi)有發(fā)生改變的征兆婿奔,那么也許沒(méi)有必要主動(dòng)分離它們
  • 單一職責(zé)原則的優(yōu)優(yōu)缺點(diǎn)
    • 優(yōu)點(diǎn)
      • 降低了單個(gè)類(lèi)或者對(duì)象的 ( 復(fù)雜度 )
      • 按照 ( 職責(zé) ) 把類(lèi)和對(duì)象分解成 ( 更小粒度 )缺狠,有利于 ( 代碼復(fù)用 ) ( 單元測(cè)試 ) 等
      • 當(dāng)一個(gè)職責(zé)變化時(shí)问慎,不會(huì)影響到其他職責(zé)
    • 缺點(diǎn)
      • 增加了代碼復(fù)雜度
      • 增加了對(duì)象之間相互聯(lián)系的難度

(2.2) 開(kāi)放封閉原則

  • 關(guān)鍵詞
    • 開(kāi)放-封閉原則,滿(mǎn)足類(lèi),對(duì)象,模塊长酗,函數(shù)是 ( 可擴(kuò)展的 )旋恼,但是是 ( 不可修改的 )
    • 即當(dāng)需要給程序添加功能或者修改功能時(shí),可以嘗試添加代碼,但是不能去修改源代碼
  • 案例
    • 用對(duì)象的 ( 多態(tài) ) 來(lái)消除 ( 條件分支 )
    • 將 ( 穩(wěn)定不變的部分 ) 和 ( 容易變化的部分 ) 分開(kāi),則在系統(tǒng)演化迭代的過(guò)程中,只需要去修改經(jīng)常變化的部分挖腰,變化的部分使用 ( 鉤子函數(shù) ) 和 ( 回調(diào)函數(shù) )
  • 優(yōu)點(diǎn)
    • 原來(lái)的代碼不用修改
    • 可以復(fù)用原來(lái)沒(méi)有修改的代碼
  • 開(kāi)放封閉原則總結(jié)
    • 不管是具體的各種設(shè)計(jì)模式,還是更抽象的面向?qū)ο笤O(shè)計(jì)原則练湿,比如單一職責(zé)原則猴仑、最少知識(shí)原則、依賴(lài)倒置原則等肥哎,都是為了讓程序遵守開(kāi)放-封閉原則而出現(xiàn)的

(2.3) 最少知識(shí)原則

  • 概念
    • 一個(gè) ( 對(duì)象辽俗,類(lèi),模塊篡诽,函數(shù)崖飘,變量 ) 等應(yīng)該對(duì)其他對(duì)象有最少的了解,減少對(duì)象之間的耦合

(2.4) 里氏替換原則

  • 概念
    • 所有引用 ( 基類(lèi) ) 的地方杈女,必須能夠使用其 ( 子類(lèi) ) 直接替換
  • 特點(diǎn)
    • 子類(lèi)必須實(shí)現(xiàn)父類(lèi)的所有方法朱浴,即繼承父類(lèi)所有的方法和屬性
    • 子類(lèi)可以有自己的屬性和方法 ( 重寫(xiě)或者添加新的屬性 )
    • 覆蓋或者實(shí)現(xiàn)父類(lèi)的方法時(shí),入?yún)⒖梢员环糯蟠镆敵隹梢员豢s小

(2.5) 依賴(lài)倒置原則

  • 模塊間依賴(lài)通過(guò)抽象(比如:接口interface)發(fā)生翰蠢,實(shí)現(xiàn)類(lèi)(實(shí)現(xiàn)類(lèi)可以去實(shí)現(xiàn)接口中的方法)之間不直接依賴(lài)
  • ( 實(shí)現(xiàn)類(lèi) ) 依賴(lài)于 ( 接口或抽象類(lèi) )
  • ( 接口或者抽象類(lèi) ) 不依賴(lài)于 ( 實(shí)現(xiàn)類(lèi) ) - 什么是抽象類(lèi)類(lèi)?
  • 什么是抽象類(lèi)類(lèi)啰劲?
    • 如果以一個(gè)類(lèi)中沒(méi)有足夠的信息來(lái)描繪一個(gè)具體的對(duì)象梁沧,這樣的類(lèi)就是抽象類(lèi)
    • 抽象類(lèi)不能實(shí)例化對(duì)象,所以抽象類(lèi)必須被繼承才能使用

(2.6) 接口隔離原則

  • 客戶(hù)端不應(yīng)該依賴(lài)于它不需要的接口
  • 建立單一的接口

(三) 工廠模式

(3.1) 簡(jiǎn)單工廠模式

  • 在簡(jiǎn)單工廠模式中蝇裤,是由工廠來(lái)創(chuàng)建產(chǎn)品的趁尼,即是老板也是服務(wù)員
abstract class Animal {  // 抽象類(lèi)不需要自己實(shí)現(xiàn)方法
  constructor(public name: string) {
    // this.name = name
  }
}
class Cat extends Animal { } // 繼承
class Dog extends Animal { } // 繼承

// 簡(jiǎn)單工廠模式
// 通過(guò)傳入 (類(lèi)型) 在工廠類(lèi)中根據(jù)傳入的類(lèi)型,分別調(diào)用給構(gòu)造函數(shù)去生產(chǎn)對(duì)應(yīng)的實(shí)例
class AnimalFactory {
  static create(name: string) { // static 靜態(tài)方法可以通過(guò)類(lèi)本身去調(diào)用
    switch (name) { // 根據(jù)傳入的類(lèi)型猖辫,調(diào)用不同的構(gòu)造函數(shù),創(chuàng)建不同的實(shí)例
      case 'cat':
        return new Cat('cat')
      case 'dog':
        return new Dog('dog')
      default:
        return new Error('出錯(cuò)了')
    }
  }
}

const dog = AnimalFactory.create('dog') // 生產(chǎn)dog
const cat = AnimalFactory.create('cat') // 生產(chǎn)cat
console.log(dog)
console.log(cat)

(3.2) 工廠方法模式

  • 在簡(jiǎn)單工廠模式中砚殿,是由工廠來(lái)創(chuàng)建產(chǎn)品的啃憎,即是老板也是服務(wù)員
  • 在工廠方法模式中,不再由工廠來(lái)創(chuàng)建產(chǎn)品似炎,而是先創(chuàng)建具體的工廠辛萍,然后具體的工廠來(lái)創(chuàng)建產(chǎn)品
  • 即由原來(lái)的老板做悯姊,變成了發(fā)命令讓別人來(lái)做
  • 即由工廠命令其他工廠來(lái)生產(chǎn)產(chǎn)品
abstract class Animal { // ----------------------------------------- 產(chǎn)品
  // 抽象類(lèi)不需要自己實(shí)現(xiàn)方法
  constructor(public name: string) {
    // this.name = name
  }
}
class Cat extends Animal { } // ------------------------------------ 具體產(chǎn)品 cat
class Dog extends Animal { } // ------------------------------------ 具體產(chǎn)品 dog

abstract class AnimalFactory { // ---------------------------------- 具體類(lèi)型的工廠抽象類(lèi)
  abstract createAnimal(): Animal
}
class CatFactory extends AnimalFactory { // ------------------------ 創(chuàng)建cat的工廠,實(shí)現(xiàn)類(lèi)
  // 實(shí)現(xiàn)類(lèi) 實(shí)現(xiàn) 抽象類(lèi)的方法
  createAnimal() {
    return new Cat('cat')
  }
}
class DogFactory extends AnimalFactory { // ------------------------ 創(chuàng)建dog的工廠贩毕,實(shí)現(xiàn)類(lèi)
  // 實(shí)現(xiàn)類(lèi) 實(shí)現(xiàn) 抽象類(lèi)的方法
  createAnimal() {
    return new Dog('dog')
  }
}

class Factory { // ------------------------------------------------- 工廠類(lèi)
  // --------------------------------------------------------------- 根據(jù)類(lèi)型悯许,讓具體的工廠去生產(chǎn)產(chǎn)品
  static create(name: string) { // static 靜態(tài)方法可以通過(guò)類(lèi)本身去調(diào)用
    switch (name) { // 根據(jù)傳入的類(lèi)型,調(diào)用不同的構(gòu)造函數(shù)辉阶,創(chuàng)建不同的實(shí)例
      case 'cat':
        return new CatFactory().createAnimal()
      case 'dog':
        return new DogFactory().createAnimal()
      default:
        return new Error('出錯(cuò)了')
    }
  }
}

const dog = Factory.create('dog')
const cat = Factory.create('cat')
console.log(dog)
console.log(cat)

(3.3) 抽象工廠模式

abstract class Cat {}
abstract class Dog {}
class ChinessCat extends Cat {} // 中國(guó)貓
class ChinessDog extends Dog {} // 中國(guó)狗
class EnglishCat extends Cat {} // 美國(guó)貓
class EnglishDog extends Dog {} // 美國(guó)狗

abstract class AnimalFactory { // ------------------------------- 抽象工廠類(lèi) => 抽象動(dòng)物工廠
  abstract createCat(): Cat
  abstract createDog(): Dog
}

class ChineseAnimalFactory extends AnimalFactory { // ----------- 實(shí)現(xiàn)類(lèi) => 中國(guó)動(dòng)物工廠
  createCat() {
    return new ChinessCat()
  }
  createDog() {
    return new ChinessDog()
  }
}

class EnglishAnimalFactory extends AnimalFactory { // ----------- 實(shí)現(xiàn)類(lèi) => 美國(guó)動(dòng)物工廠
  createCat() {
    return new EnglishCat()
  }
  createDog() {
    return new EnglishDog()
  }
}

const chineseAnimal = new ChineseAnimalFactory() // ------------- 中國(guó)動(dòng)物
const chineseCat = chineseAnimal.createCat() // ----------------- 中國(guó)貓
console.log(chineseCat)

(四) 適配器模式 adapter

  • 適配器模式又稱(chēng)包裝器模式先壕,將一個(gè)類(lèi)的接口轉(zhuǎn)化為用戶(hù)需要的另一個(gè)接口,解決類(lèi)或?qū)ο笾g接口不兼容問(wèn)題
  • 舊的接口和使用者不兼容
  • 中間加一個(gè)適配器轉(zhuǎn)換接口
  • 總結(jié)
    • 適配器模式就是為了解決 ( 適配兩個(gè)以上接口不兼容的問(wèn)題 ) 和 ( 外觀模式 ) 的核心思路保持一致
    • 適配器模式adapter谆甜,也被稱(chēng)作 ( 包裝器模式wrapper )
      • 本質(zhì)上是在原有邏輯上再包裝一層
      • 類(lèi)比 ( 高階組件 )
1
// Rmb 是需要被適配的類(lèi)
class Rmb {
  output() {
    return '100rmb'
  }
}

abstract class Money {
  abstract transform(): string
}

class MoneyAdaptor extends Money { // 適配器實(shí)現(xiàn)類(lèi)
  rmb: Rmb
  constructor(rmb: Rmb) {
    super()
    this.rmb = rmb
  }
  transform() {
    return this.rmb.output() + '轉(zhuǎn)成美元'
  }
}

const dollar = new MoneyAdaptor(new Rmb())
console.log(dollar.transform());
2
適配器模式在javascript中的運(yùn)用 
- 概念:適配器就是將不適配東西適配起來(lái)垃僚,比如:手機(jī)轉(zhuǎn)接頭,轉(zhuǎn)換器等
- 案例:將 ( 小寫(xiě)字符串 ) 適配成 ( 大寫(xiě)字符串 )
---

class Lower {
  getSize = () => "size";
}

class Adapter {
  lower = new Lower().getSize();
  getSize = () => this.lower.toUpperCase(); // 轉(zhuǎn)成大寫(xiě)
}

const upper = new Adapter().getSize();

(4.1) 適配器模式有哪些運(yùn)用

  • axios中區(qū)分瀏覽器和node端時(shí)的adaptor函數(shù)
  • vue中的computed計(jì)算屬性

(4.2) 適配器模式應(yīng)用案例 - axios

  • axios中的adapter函數(shù)就會(huì)根據(jù)系統(tǒng)的類(lèi)型去調(diào)用不同的請(qǐng)求方法规辱,比如瀏覽器中使用XMLHttpRequest谆棺,而在node環(huán)境中使用http模塊,從而抹平差異化
  • axios源碼中的adapter
1. var adapter = config.adapter || defaults.adapter;

2. adapter(config).then() // 不管是什么環(huán)境罕袋,瀏覽器或者node都返回一個(gè)promise

3. defaultes.adapter 如下
var defaults = {
  adapter: getDefaultAdapter()
}
function getDefaultAdapter() {
  var adapter;
  if (typeof XMLHttpRequest !== 'undefined') {
    adapter = require('./adapters/xhr'); // 瀏覽器環(huán)境
  } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
    adapter = require('./adapters/http'); // node環(huán)境
  }
  return adapter;
}
  • 手寫(xiě)一個(gè)axios中的adapter函數(shù)
axios({
  method: "GET",
  url: "www.baidu.com",
}).then(
  (value) => console.log(value),
  (reason) => console.error(reason)
);
// 設(shè)計(jì)模式y(tǒng)uanze
// 1. 單一職責(zé)原則 => 一個(gè)函數(shù)只實(shí)現(xiàn)一個(gè)邏輯
// 2. 開(kāi)放封閉原則 => 可擴(kuò)展改淑,不可修改
// 3. 最少知識(shí)原則 => 模塊,函數(shù)浴讯,方法朵夏,變量都要盡量依賴(lài)其他類(lèi)和對(duì)象
// 4. 里氏替換原則 => 基類(lèi)可以用子類(lèi)直接替換
// 5. 接口隔離原則
// 6. 依賴(lài)倒置原則 => 實(shí)現(xiàn)類(lèi) 依賴(lài) 接口或者抽象類(lèi)

// 瀏覽器端
function xhrAdaptor(config) {
  const { method, url } = config;
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open(method, url, true);
    xhr.setRequestHeader("Content-Type", "application/json"); // setRequestHeader 必須是在 open之后 send之前
    xhr.responseType = "json";
    xhr.onreadystatechange = function () {
      if (xhr.readyState !== 4) {
        return;
        // readyState
        // 0 UNSENT ------------- xhr實(shí)例已經(jīng)被創(chuàng)建,open()方法未被調(diào)用
        // 1 OPEND -------------- open()方法被調(diào)用兰珍,send()方法未被調(diào)用侍郭,setRequestHeader() 可以被調(diào)用
        // 2 HEADERS_RECEIVED --- send()方法被調(diào)用,響應(yīng)頭和響應(yīng)狀態(tài)已經(jīng)返回
        // 3 LOADING ------------ 響應(yīng)體(response entity body)正在下載中掠河,此狀態(tài)下通過(guò) xhr.response 可能已經(jīng)有了響應(yīng)數(shù)據(jù)
        // 4 DONE --------------- 整個(gè)數(shù)據(jù)傳輸過(guò)程已經(jīng)完成亮元,無(wú)論本次請(qǐng)求是成功還是失敗
      }
      if (xhr.status === 200) {
        // readyState === 4 && status === 200
        return resolve(xhr.responseText);
      } else {
        return reject(new Error(xhr.statusText));
      }
    };
    xhr.onerror = function () {
      console.error("error");
    };
    // xhr.onload = function() {
    //     if (xhr.status > 200 && xhr.status < 300 || xhr.status === 304) {
    //         return resolve(xhr.responseText)
    //     }
    // }
    xhr.send();
  });
}

// 服務(wù)器端
function httpAdaptor(config) {
  const { method, url } = config
  const http = requrie('http')
  const {hostname, port, path} = url.parse(url)
  return new Promise((resolve, reject) => {
    // http模塊
    const options = {
      method,
      hostname,
      port,
      path
    };
    let req = http.request(options, function (response) {
      let chunks = [];
      response.on("data", function (chunk) {
        chunks.push(chunk);
      });
      response.on("end", function () {
        const result = Buffer.concat(chunks).toString();
        return resolve(result);
      });
    });
    req.on("error", function (error) {
      return reject(error);
    });
  });
}


function getDefaultAdaptor() {
  // ---------------------- 適配器模式,根據(jù)環(huán)境調(diào)用不同的方法
  let adaptor;
  if (typeof XMLHttpRequest !== "undefined") {
    // ------ 瀏覽器環(huán)境
    adaptor = xhrAdaptor;
  }
  if (typeof process !== "undefined") {
    // ------------- node環(huán)境
    adaptor = httpAdaptor;
  }
  return adaptor;
}

function axios(config) {
  const adaptor = getDefaultAdaptor();
  return adaptor(config);
  // axios返回值就是一個(gè)promise對(duì)象唠摹,無(wú)論是瀏覽器端還是node端
}

(五) 裝飾器模式

  • 裝飾器模式是為已有功能更多功能的一種方式爆捞,是一種結(jié)構(gòu)型設(shè)計(jì)模式,是對(duì)原有類(lèi)進(jìn)行擴(kuò)展
  • 是一種依靠 ( 組合 ) 來(lái)實(shí)現(xiàn) ( 類(lèi)的功能擴(kuò)展 )勾拉,并且支 ( 持多層嵌套 ) 的設(shè)計(jì)模式
  • 如果直接添加邏輯會(huì)違反 ( 單一職責(zé)原則 ) 和 ( 開(kāi)放封閉原則 )
  • 常用的裝飾器有 ( 類(lèi)裝飾器 ) ( 屬性裝飾器 ) ( 方法裝飾器 ) ( 參數(shù)裝飾器 )
abstract class Shape { // 形狀抽象類(lèi)
  abstract draw(): void;
}

class Circle extends Shape { // 形狀子類(lèi) 圓
  draw() {
    console.log("繪制圓");
  }
}

class Rectagle extends Shape { // 形狀子類(lèi) 矩形
  draw() {
    console.log("繪制矩形");
  }
}

abstract class Color extends Shape { // Color 也繼承 Shape
  constructor(public shape: Shape) {
    super();
  }
  abstract draw(): void;
}

class Red extends Color {
  draw() {
    this.shape.draw(); // 調(diào)用傳入的參數(shù)實(shí)例的draw方法煮甥,在new Red()時(shí)傳入的參數(shù)是new Circle()
    console.log("繪制紅色");
  }
}
class Yellow extends Color {
  draw() {
    this.shape.draw();
    console.log("繪制黃色");
  }
}

const redCircle = new Red(new Circle());
redCircle.draw() // 調(diào)用實(shí)例上的draw方法
image.png

(5.1) 裝飾器模式在前端中的運(yùn)用

  • 2021/09/22 更新
  • 表單驗(yàn)證
    • 在 ( 表單提交時(shí),先做表單驗(yàn)證 ) 的工作
    • 核心函數(shù):submit submit.before validate
/**
 * 借助裝飾者模式藕赞,很容易衍生出 AOP 面向切面編程的概念
 * - 場(chǎng)景:典型場(chǎng)景就是對(duì)表單的驗(yàn)證成肘,我們將把表單輸入邏輯校驗(yàn)的 validata 函數(shù)融入到 before 邏輯當(dāng)中
 * - 具體:
 *   1. 在提交表單時(shí),執(zhí)行 ( submit ) 函數(shù)斧蜕,因?yàn)樵?( Function.prototype.before ) 掛載了 ( before ) 函數(shù)双霍,被所有實(shí)例函數(shù)所繼承
 *   2. 我們并不直接submit函數(shù),而是調(diào)用 ( submit.before ) 從而在 sumbit 之前執(zhí)行驗(yàn)證函數(shù) ( validate ) 從而在執(zhí)行sumbit之前做表單驗(yàn)證功能
 */
Function.prototype.before = function(beforefn) {
  const self = this
  return function() {
    if (beforefn.apply(this, arguments) === false) return // 表示執(zhí)行驗(yàn)證邏輯時(shí),驗(yàn)證未通過(guò)
    return self.apply(this, arguments) // this是調(diào)用before方法時(shí)所在的對(duì)象洒闸,是 submitBtn 在調(diào)用before染坯,所以在了的 self 就是 submitBtn 函數(shù)
  }
}

const validate = function() {
  // 表單驗(yàn)證邏輯
}

const formSubmit = function() {
  // 表達(dá)提交邏輯
  ajax('http:// xxx.com/login', param)
}

submitBtn.onclick = function() {
  formSubmit.before(validate)
}

資料

設(shè)計(jì)原則1 https://juejin.cn/post/6844904025565970439
設(shè)計(jì)原則2 https://juejin.cn/post/6847902225717854215
裝飾器模式1 https://juejin.cn/post/6914235611545092109
裝飾器模式2 https://juejin.cn/post/6881897639001751560

vscode=>codeRunner=>ts-node出現(xiàn)亂碼解決方案如下
https://github.com/formulahendry/vscode-code-runner/issues/632

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市丘逸,隨后出現(xiàn)的幾起案子单鹿,更是在濱河造成了極大的恐慌,老刑警劉巖深纲,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仲锄,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡囤萤,警方通過(guò)查閱死者的電腦和手機(jī)昼窗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)涛舍,“玉大人澄惊,你說(shuō)我怎么就攤上這事「谎牛” “怎么了掸驱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)没佑。 經(jīng)常有香客問(wèn)我毕贼,道長(zhǎng),這世上最難降的妖魔是什么蛤奢? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任鬼癣,我火速辦了婚禮,結(jié)果婚禮上啤贩,老公的妹妹穿的比我還像新娘待秃。我一直安慰自己,他們只是感情好痹屹,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布章郁。 她就那樣靜靜地躺著,像睡著了一般志衍。 火紅的嫁衣襯著肌膚如雪暖庄。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天楼肪,我揣著相機(jī)與錄音培廓,去河邊找鬼。 笑死春叫,一個(gè)胖子當(dāng)著我的面吹牛医舆,可吹牛的內(nèi)容都是我干的俘侠。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蔬将,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了央星?” 一聲冷哼從身側(cè)響起霞怀,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎莉给,沒(méi)想到半個(gè)月后毙石,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡颓遏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年徐矩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叁幢。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡滤灯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出曼玩,到底是詐尸還是另有隱情鳞骤,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布黍判,位于F島的核電站豫尽,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏顷帖。R本人自食惡果不足惜美旧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贬墩。 院中可真熱鬧榴嗅,春花似錦、人聲如沸震糖。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吊说。三九已至论咏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間颁井,已是汗流浹背厅贪。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留雅宾,地道東北人养涮。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親贯吓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子懈凹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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