欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入淺出JavaScript前端中的設計模式

 更新時間:2023年05月15日 09:05:18   作者:世界和平  
這篇文章主要介紹了JavaScript前端中的設計模式,設計模式是一套被反復使用,多數人知曉的,經過分類編目的,代碼設計經驗的總結,感興趣想要詳細了解可以參考下文

關于設計模式

軟件設計模式,又稱設計模式,是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。它描述了在軟件設計過程中的一些不斷重復發(fā)生的問題,以及該問題的解決方案。也就是說,它是解決待定問題的一系列套路,是前輩們的代碼設計經驗的總結,具有一定的普遍性,可以重復使用。其目的是為了提高代碼的可重用性、代碼的可讀性和代碼的可靠性。

簡單地說就是一些通用的代碼編寫方式,它是經過不斷考驗得出的一些總結道理,按照這樣的模式去編寫我們的代碼,沿著前人留下來的經驗,我們就可以編寫出詩一般的代碼。

關于設計模式,我們需要知道五大基本原則(SOLID):

(1)單一職責原則:一個類,應該僅有一個引起它變化的原因,簡而言之,就是功能要單一。

(2)開放封閉原則:對擴展開放,對修改關閉。

(3)里氏替換原則:基類出現(xiàn)的地方,子類一定出現(xiàn)。兩個字總結-繼承。

(4)接口隔離原則:一個接口應該是一種角色,不該干的事情不敢,該干的都要干。簡而言之就是降低耦合、減低依賴。

(5)依賴翻轉原則:針對接口編程,依賴抽象而不依賴具體。所編寫的對象不應該跟具體的實例掛鉤,應該更偏抽象的概念。

更具體地描述設計模式的好處,有以下幾點:

①良好的封裝,不會讓內部變量污染外部

②封裝好的代碼可以作為一個模塊給外部調用。外部無需了解細節(jié),只需按約定的規(guī)范調用。

③對擴展開放,對修改關閉,即開放關閉原則。外部不能修改內部代碼,保證了內部的正確性;又留出擴展接口,提高了靈活性。

像我們常用的各大框架,如React,Vue等都有不同設計模式的應用,Vue中使用了觀察者模式和發(fā)布-訂閱模式。

七種常見的設計模式

設計模式一共分為3大類23種,這里主要介紹常用的幾種。

①創(chuàng)建型模式:單例模式、工廠模式、建造者模式;

②結構型模式:適配器模式、裝飾器模式、代理模式;

③行為型模式:策略模式、觀察者模式、發(fā)布訂閱模式、職責鏈模式、中介者模式。

單例模式

單例模式:一個類只有一個實例,并提供一個訪問他的全局訪問點,即一個類只生成一個唯一的實例。

我們在一個類中聲明屬性instance,當調用函數getInstance時,我們判斷instance是否已經存在實例,若存在則訪問該instance對象,若不存在則創(chuàng)建。

class Singleton {
    let _instance = null;
    static getInstance() {
        if (!Singleton._instance) {
          Singleton.instance = new Singleton()
        }
        // 如果這個唯一的實例已經存在,則直接返回
        return Singleton._instance
    }
}
const s1 = Singleton.getInstance()
const s2 = Singleton.getInstance()

Vuex就是一個典型的單例模式使用案例, store對象就是一個單例對象。

根據其功能代碼,我們可以看出單例模式的優(yōu)劣點都在哪里。

優(yōu)點: 節(jié)約資源,保證訪問的一致性。

缺點: 擴展性不友好,因為單例模式一般自行實例化,沒有接口。

工廠模式

這個模式我們就非常常用了,聲明一個class,然后根據傳進來的參數去生成對應的實例對象,就是所謂的工廠模式。每一個類就像一個已經開設好的工廠,我們只需要告訴我們的需求,它就會生成我們想要的一個對象返回。

class Restaurant{
    constructor(){
        this.menuData = {};
    }
    // 獲取菜品
    getDish(dish){
        if(!this.menuData[menu]){
            console.log("菜品不存在,獲取失敗");
            return;
        }
        return this.menuData[menu];
    },
    // 添加菜品
    addMenu(menu,description){
        if(this.menuData[menu]){
            console.log("菜品已存在,請勿重復添加");
            return;
        }
        this.menuData[menu] = menu;
    }
    // 移除菜品
    removeMenu(menu){
        if(!this.menuData[menu]){
            console.log("菜品不存在,移除失敗");
            return;
        }
        delete this.menuData[menu];
    },
}
class Dish{
    constructor(name,description){
        this.name = name;
        this.description = description;
    }
    eat(){
        console.log(`I'm eating ${this.name},it's ${`this.description);
    }
}

優(yōu)點:

  • 良好的封裝,訪問者無需了解創(chuàng)建過程,代碼結構清晰。
  • 擴展性良好,通過工廠方法隔離了用戶和創(chuàng)建流程,符合開閉原則。
  • 解耦了高層邏輯和底層產品類,符合最少知識原則,不需要的就不要去交流;

缺點:

缺點就是如果我們的類定義太過抽象復雜了,會出現(xiàn)閱讀性的問題。

適配器模式

這個模式也很好理解,相當于我們平時使用的一些產品,如投影儀之類的,如果我們的電線無法適配到我們的屏幕,我們就需要借助一個中間的適配器,讓兩者可以溝通起來。

interface bookDataType1 {
  book_id: number;
  status: number;
  create: string;
  update: string;
}
interface bookDataType2 {
  id: number;
  status: number;
  createTime: number;
  updateAt: string;
}
interface bookDataType3 {
  book_id: number;
  status: number;
  createTime: number;
  updateAt: number;
}
const getTimeStamp = function (str: string): number {
  //.....轉化成時間戳
  return timeStamp;
};
//適配器
export const bookDataAdapter = {
  adapterType1(list: bookDataType1[]) {
    const bookDataList: bookData[] = list.map((item) => {
      return {
        book_id: item.book_id,
        status: item.status,
        createAt: getTimeStamp(item.create),
        updateAt: getTimeStamp(item.update),
      };
    });
    return bookDataList;
  },
  adapterType2(list: bookDataType2[]) {
    const bookDataList: bookData[] = list.map((item) => {
      return {
        book_id: item.id,
        status: item.status,
        createAt: item.createTime,
        updateAt: getTimeStamp(item.updateAt),
      };
    });
    return bookDataList;
  },
  adapterType3(list: bookDataType3[]) {
    const bookDataList: bookData[] = list.map((item) => {
      return {
        book_id: item.book_id,
        status: item.status,
        createAt: item.createTime,
        updateAt: item.updateAt,
      };
    });
    return bookDataList;
  },
};

優(yōu)點: 可以使原有邏輯得到更好的復用,有助于避免大規(guī)模改寫現(xiàn)有代碼,為了不改動原有的代碼而做出的一種妥協(xié);

缺點:會讓系統(tǒng)變得零亂,明明調用 A,卻被適配到了 B,如果濫用,那么對可閱讀性不太友好。簡而言之搞復雜了,所以通常建議不要出現(xiàn)以上這樣的格式問題,應該跟后端溝通好數據。

裝飾器模式

典型的大腸包小腸,當前使用的對象無法滿足我們的全部需求,于是乎我們建一個新的類,再把這個對象在類中進行擴展,再生成一個新的對象。

策略模式

這個是相當相當常用,而且很好用的一個設計模式,可以讓我們根據不同的選擇去實現(xiàn)對應的功能,省略了大量的if,else。

比如我們現(xiàn)在有一個需求判斷,比如我現(xiàn)在要根據別人給我的不同食材去制造料理,最暴力常規(guī)那就是if,else多寫幾個就解決了。但是這里如果我們用策略模式就可以用很清晰,很簡潔的代碼去解決這個問題。

if ( 'food' == '蘋果') {
      水煮()
} else if ('food' == '胡蘿卜') {
      炒了()
} else if ('food' == '魚') {
      清蒸()
} else if ('food' == '豬肉') {
      炸了()
} else if ('food' == '牛肉') {
      烤了()
} else {
      生吃()
}
// 用了策略模式,看起來舒服多了
let wayObj = {
    '蘋果': 水煮(),
    '胡蘿卜': 炒了(),
    '魚': 清蒸(),
    '豬肉': 炸了(),
    '牛肉': 烤了(),
    '不知道': 生吃()
}

觀察者模式

這個模式從名字就可以看出來它是干嘛的,觀察者重點就是觀察,有兩個對象,一個是觀察,一個是被觀察,被觀察發(fā)生了變化,那我們觀察的對象就可以知道這個變化。

觀察者模式有一個別名叫“發(fā)布-訂閱模式”,或者說是“訂閱-發(fā)布模式”,訂閱者和訂閱目標是聯(lián)系在一起的,當訂閱目標發(fā)生改變時,逐個通知訂閱者。我們可以用報紙期刊的訂閱來形象的說明,當你訂閱了一份報紙,每天都會有一份最新的報紙送到你手上,有多少人訂閱報紙,報社就會發(fā)多少份報紙,報社和訂報紙的客戶就是上面文章開頭所說的“一對多”的依賴關系。

// 觀察者模式 被觀察者Subject 觀察者Observer Subject變化 notify觀察者
let observerIds = 0;
// 被觀察者Subject
class Subject {
  constructor() {
    this.observers = [];
  }
  // 添加觀察者
  addObserver(observer) {
    this.observers.push(observer);
  }
  // 移除觀察者
  removeObserver(observer) {
    this.observers = this.observers.filter((obs) => {
      return obs.id !== observer.id;
    });
  }
  // 通知notify觀察者
  notify() {
    this.observers.forEach((observer) => observer.update(this));
  }
}
// 觀察者Observer
class Observer {
  constructor() {
    this.id = observerIds++;
  }
  update(subject) {
    // 更新
  }
}

發(fā)布-訂閱模式

其實上面也說了,跟觀察者模式是有異曲同工之妙的,但是它可以是一個一對多的關系,而且它需要一個中間人。

class Event {
  constructor() {
    this.eventEmitter = {};
  }
  // 訂閱
  on(type, fn) {
    if (!this.eventEmitter[type]) {
      this.eventEmitter[type] = [];
    }
    this.eventEmitter[type].push(fn);
  }
  // 取消訂閱
  off(type, fn) {
    if (!this.eventEmitter[type]) {
      return;
    }
    this.eventEmitter[type] = this.eventEmitter[type].filter((event) => {
      return event !== fn;
    });
  }
  // 發(fā)布
  emit(type) {
    if (!this.eventEmitter[type]) {
      return;
    }
    this.eventEmitter[type].forEach((event) => {
      event();
    });
  }
}

到此這篇關于深入淺出JavaScript前端中的設計模式的文章就介紹到這了,更多相關JS設計模式內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • javascript實現(xiàn)信息增刪改查的方法

    javascript實現(xiàn)信息增刪改查的方法

    這篇文章主要介紹了javascript實現(xiàn)信息增刪改查的方法,實例分析了javascript操作頁面元素實現(xiàn)針對頁面信息的增刪改查功能,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • js阻止冒泡和默認事件(默認行為)詳解

    js阻止冒泡和默認事件(默認行為)詳解

    這篇文章主要為大家詳細介紹了js阻止冒泡和默認事件,即默認行為,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • JavaScript實現(xiàn)獲得所有兄弟節(jié)點的方法

    JavaScript實現(xiàn)獲得所有兄弟節(jié)點的方法

    這篇文章主要介紹了JavaScript實現(xiàn)獲得所有兄弟節(jié)點的方法,實例分析了javascript節(jié)點遍歷的相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • js倒計時小程序

    js倒計時小程序

    js倒計時代碼,可以精確到天和精確到秒
    2013-11-11
  • JavaScript中的16進制字符介紹

    JavaScript中的16進制字符介紹

    最早接觸到\unnn之類的字符是在微軟的官網上。當時在網上找了一下這中字符格式,卻不知道該搜什么
    2011-10-10
  • 判斷l(xiāng)i是否有樣式的js代碼

    判斷l(xiāng)i是否有樣式的js代碼

    下面的代碼注意實現(xiàn)先判斷l(xiāng)i是否有樣式,如果沒有,就添加一個樣式,原理呢,就是批量檢測li的className屬性
    2008-09-09
  • javascript稀疏數組(sparse array)和密集數組用法分析

    javascript稀疏數組(sparse array)和密集數組用法分析

    這篇文章主要介紹了javascript稀疏數組(sparse array)和密集數組用法,分析javascript稀疏數組和密集數組的功能、定義與使用方法,需要的朋友可以參考下
    2016-12-12
  • javascript簡單性能問題及學習筆記

    javascript簡單性能問題及學習筆記

    最近在看一本書:《高性能javaScript》,發(fā)現(xiàn)自己平時寫js存在很多小細節(jié)上的問題,雖然這些問題不會導致程序運行出錯,但是會導致界面加載變慢,用戶體驗變差,那么我們就來細細數一下應該注意的地方吧
    2014-02-02
  • javascript 取小數點后幾位幾種方法總結

    javascript 取小數點后幾位幾種方法總結

    這篇文章主要介紹了javascript 取小數點后幾位幾種方法總結的相關資料,這里提供了四種方法,幫助大家整理,需要的朋友可以參考下
    2017-08-08
  • 如何通過Proxy實現(xiàn)JSBridge模塊化封裝

    如何通過Proxy實現(xiàn)JSBridge模塊化封裝

    這篇文章主要介紹了如何通過Proxy實現(xiàn)JSBridge模塊化封裝,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-10-10

最新評論