JavaScript 設計模式 : 生活中的'介面卡'和'裝飾者'模式

莊文達發表於2017-05-09

首先很抱歉近期公務繁忙沒來得及更新...... 為了適應節奏,先先丟擲兩個我認為相對簡單、常用的用來節省開發效率的模式,使用的場景也是很多的,相對沒有什麼難點,這裡結合場景我總結了一下。(本章適合快速閱讀)


介面卡模式

  • 組建與元件間的適配
  • 類與類之間的適配
  • 方法與方法間的適配
  • 資料結構和資料結構之間的適配

舉個栗子:

usb目前已經不滿足我們主流手機的快充功能了,需要用到type-c介面,我們肯定不會把線剪短換上一個type-c的頭的,我們完全可以通過買一個usb轉type-c的轉接頭來解決我們這個問題。 再多的例子就不講了:)

underscore介面卡

假設,注意是假設,公司有一個框架NB.js,他的語法以及實現形式基本和underscore.js相似,例如each操作:

//NB.js
NB.each([1,2,3],function(key,value){
    console.log(this.location.href + '?'+value)
},window)
複製程式碼
//underscore.js
_.each([1,2,3],function(value,key){
    console.log(this.location.href + '?'+value)
},window)
複製程式碼

兩個框架的key,value順序是不一樣的。 公司新招了一批同事,他們用過underscore.js但是完全沒聽說過NB.js,公司時間緊任務重,領導決定,先讓公司同事使用underscore的方式使用內部的框架,逐步完善NB.js文件。

這個任務交給你,但總不能對NB.js進行大量的修改,就像上面轉接頭的問題,我們換一個轉接頭就好了:

window.NB = NB = _ ; //underscore轉NB介面卡。
複製程式碼

引數介面卡

function doSomeThing(name,id,color,height,width){
    
}
doSomeThing('input1','99899','red','200','200')
複製程式碼

這樣的一個函式有多個固定順序的引數,我們知道顯然是不友好的,我們寫函式的時候一定要避免這樣的問題,這樣會顯得很low,首先就要想到適配

function doSomeThing(obj){
    var adapter = {
        name:'name',
        id:'001',
        color:'yellow',
        height:'100',
        width:'100'
    };
    for(var i in adapter){
        adapter[i] = obj[i] || adapter[i];
    }
    console.log(adapter);
}

var obj = {color:'red'}
doSomeThing(obj)
//object {name: "name", id: "001", color: "red", height: "100", width: "100"}
複製程式碼

上面的問題其實很多同學早就知道了,還有一種情況就是,前後分離的開發過程中,後臺人員習慣返回的格式跟全端人員預期的不一樣,我們也可以進行適配。

// 後端返回Object,前端需要Array

$.ajax({
    url:xxx.action,
    success:function(data){
        doSomeThing(dataAdapter(data));
    }
})

function dataAdapter(obj){
    return [obj['name],obj['id'],obj['color'],obj['height'],obj['width']];
}
複製程式碼

像這樣,後端有任何變化我們只需要修改dataAdapter函式就好,其他的通途大家自行腦補:), 其實各種設計模式的宗旨都是低耦合,易維護

裝飾模式

在原型不變的基礎是,通過對他進行包裝,附加屬性,附加方法,使原有的物件、函式能滿足更復雜的需求。因為已經說了裝飾,所以只是新增新功能時候可以用。

舉個最簡單的例子: 系統中有 一些 按鈕,目前每個按鈕點選後彈出你好,現在需要在彈出你好過5秒之後在彈出再見更具體的大家自己腦補,很常見的需求。 有的人開始馬上動手寫了:


<button id="A"></button>
//原來的
 var A = document.getElementById('A');
    A.onclick = function(){
        alert(1)
    };
//修改後的
 var A = document.getElementById('A');
    A.onclick = function(){
        alert(1);
        setTimeout(function(){
            alert(2)
        },5000)
    };
    
複製程式碼

當你沾沾自喜時,你發現還有99個按鈕要改......當你真的完成了這個不可思議的任務後,你發現需求變了......好那我們還是儘快使用裝飾者模式吧:

var A = document.getElementById('A');
    A.onclick = function(){
        alert(1)
    }
    //裝飾者
    var decorator = function (id,fn){
        var dom = document.getElementById(id);
        if(typeof dom.onclick === 'function'){
            var oldClickFn = dom.onclick;
            dom.onclick = function(){
                oldClickFn();
                fn();
            }
        }else{
            dom.onclick = fn;
        }
    }
    //利用裝飾者對元素增加事件。
    decorator('A',function(){
        setTimeout(function(){
            alert(2)
        },5000)
    })
    
複製程式碼

這樣需求改了也不怕了,我們只要修改decorator函式就好了。 當然隨手寫的也有缺點,我們的引數還是按照順序來排列的,同學們可以參考上面講的介面卡模式,方便以後維護增加程式碼!decorator是全域性的,有興趣可以參考javascript名稱空間問題,總之,程式碼是越寫越優雅的。

介面卡和裝飾器的不同之處

  • 介面卡的方法是對原有物件進行適配,新增的方法與原有方法功能大致相似,只是換了一種更加便利與我們開發的形式,但是裝飾者提供的方法是有區別的,一般都是比之前的更加豐滿,彌補之前的不足之處。
  • 裝飾者模式中可以不瞭解原有功能,並且原有的方法照樣可以原封不動的使用,如果原有的方法不能用了,說明你的模式有問題,是不可取的。

PS:

最近私事比較多,設計模式的文章以後的更新頻率是一週一章,比較複雜的單獨一章,比較簡單或關聯較大的兩章並一章,本章5分鐘閱讀流水賬,希望大家共同努力。


JavaScript 設計模式 :   生活中的'介面卡'和'裝飾者'模式

相關文章