重構 - 保持函數的單一職責

1.前言

上篇文章寫了添加擴展性方面的重構,講到了開放封閉原則。學習的步伐不能就此中止,今天的文章,將會說起開發的另外一個原則:單一職責原則。通俗點說就是一個函數只作一件事,下面將會經過幾個實例,探究單一職責原則。css

2.單一職責表現形式

單一職責的定義能夠理解爲:一個對象或者方法,只作一件事。html

遵照單一職責的實例太多了,下面簡單列舉一下。數組

原生的API方面瀏覽器

trimRight()和trimLeft():trimRight 只負責去除右邊的空白,其它地方一律無論。 trimLeft 只負責去除右邊的空白,其它地方也一律不關。bash

concat(): concat 只負責鏈接兩個或更多的數組,並返回結果。不會涉及刪除數組的操做。微信

toFixed(): toFixed 只把 Number 類型的值四捨五入爲指定小數位數的數字。不會執行其它操做。函數

JQuery 的 API學習

$.each() 只負責遍歷,要處理什麼,本身再動手操做。動畫

css() 只負責設置 DOM 的 style ,不會設置 innerHTML 。ui

animate() 只負責執行 CSS 屬性集的自定義動畫,不會涉及其它操做。

說是這樣說,可是你們看着可能會有點懵,看不出來遵照單一原則有什麼好處,下面看一個實例。

3.實例-數組處理

以下例子:

現有一批的錄入學生信息,可是數據有重複,須要把數據根據 id 進行去重。而後把爲空的信息,改爲'--'。

let students=[
    {
        id:5,
        name:'守候',
        sex:'男',
        age:'',
    },
    {
        id:2,
        name:'浪跡天涯',
        sex:'男',
        age:''
    },
    {
        id:5,
        name:'守候',
        sex:'',
        age:''
    },
    {
        id:3,
        name:'鴻雁',
        sex:'',
        age:'20'
    }
];

function handle(arr) {
    //數組去重
    let _arr=[],_arrIds=[];
    for(let i=0;i<arr.length;i++){
        if(_arrIds.indexOf(arr[i].id)===-1){
            _arrIds.push(arr[i].id);
            _arr.push(arr[i]);
        }
    }
    //遍歷替換
    _arr.map(item=>{
        for(let key in item){
            if(item[key]===''){
                item[key]='--';
            }
        }
    });
    return _arr;
}
console.log(handle(students))
複製代碼

運行結果沒有問題,可是你們想一下,

1.若是改了需求,好比,學生信息不會再有重複的記錄,要求把去重的函數去掉,不管,就是整個函數都要改了,還影響到下面的操做。

2.若是項目另外一個地方也是一樣的操做,可是不須要去重。這樣只能再寫一個基本同樣的函數,由於上面的函數沒法複用。以下

function handle1(arr) {
    //數組深拷貝
    let _arr=JSON.parse(JSON.stringify(arr));
    //遍歷替換
    _arr.map(item=>{
        for(let key in item){
            if(item[key]===''){
                item[key]='--';
            }
        }
    });
    return _arr;
}
複製代碼

3.若是項目有一個地方還須要根據 ID 排序。這樣仍是得寫一個函數,由於在不能在上面的函數上面排序。

function handle2(arr) {
    //數組去重
    let _arr=[],_arrIds=[];
    for(let i=0;i<arr.length;i++){
        if(_arrIds.indexOf(arr[i].id)===-1){
            _arrIds.push(arr[i].id);
            _arr.push(arr[i]);
        }
    }
    //遍歷替換
    _arr.map(item=>{
        for(let key in item){
            if(item[key]===''){
                item[key]='--';
            }
        }
    });
    //根據ID排序
    _arr.sort((item1,item2)=>item1.id-item2.id);
    return _arr;
}
複製代碼

這樣的問題就是在於,面對需求的變化,不能靈活的處理。函數也基本沒辦法複用。

下面使用單一原則構造一下

let handle={
    //數組去重
    removeRepeat(arr){
        let _arr=[],_arrIds=[];
        for(let i=0;i<arr.length;i++){
            if(_arrIds.indexOf(arr[i].id)===-1){
                _arrIds.push(arr[i].id);
                _arr.push(arr[i]);
            }
        }
        return _arr;
    },
    //遍歷替換
    setInfo(arr){
        arr.map(item=>{
            for(let key in item){
                if(item[key]===''){
                    item[key]='--';
                }
            }
        });
        return arr;
    },
    //根據id排序
    sortForId(arr){
        return arr.sort((item1,item2)=>item1.id-item2.id);
    }
};
//去重
students=handle.removeRepeat(students);
//設置信息
students=handle.setInfo(students);
console.log(students);
複製代碼

結果同樣,並且這樣的方式,可使得方法能夠組合使用,更加的靈活,也方便複用。

若是還須要根據ID排序,就在上面代碼執行結果的基礎上,再加一行代碼便可。

//根據ID排序
students=handle.sortForId(students);
console.log(students);
複製代碼

若是原始數據不須要去重,設置完信息以後,直接排序

let students=[
    {
        id:5,
        name:'守候',
        sex:'男',
        age:'',
    },
    {
        id:2,
        name:'浪跡天涯',
        sex:'男',
        age:''
    },
    {
        id:5,
        name:'守候',
        sex:'',
        age:''
    },
    {
        id:3,
        name:'鴻雁',
        sex:'',
        age:'20'
    }
];
//設置信息
students=handle.setInfo(students);
//根據ID排序
students=handle.sortForId(students);
複製代碼

這樣操做起來,即便之後需求有改動,在可控的範圍內,能夠靈活的組合使用,函數也能夠複用。

若是以爲要讓 students 連續賦值麻煩,能夠借鑑 JQuery 的鏈式調用方式。

let ec=(function () {
    let handle=function (obj) {
        this.obj=JSON.parse(JSON.stringify(obj));
    };
    handle.prototype={
        /** * @description 去重 */
        unique(){
            //根據id數組去重
            let _arr=[],_arrIds=[];
            for(let i=0;i<this.obj.length;i++){
                if(_arrIds.indexOf(this.obj[i].id)===-1){
                    _arrIds.push(this.obj[i].id);
                    _arr.push(this.obj[i]);
                }
            }
            this.obj=_arr;
            return this;
        },
        /** * @description 設置保密信息 */
        setInfo(){
            this.obj.map(item=>{
                for(let key in item){
                    if(item[key]===''){
                        item[key]='--';
                    }
                }
            });
            return this;
        },
        sortForId(){
            this.obj.sort((item1,item2)=>item1.id-item2.id);
            return this;
        },
        /** * @description 返回處理結果 * @return {Array|*} */
        end(){
            return this.obj;
        }
    }
    //暴露構造函數接口
    return function (obj) {
        return new handle(obj);
    }
})();
let students=[
    {
        id:5,
        name:'守候',
        sex:'男',
        age:'',
    },
    {
        id:2,
        name:'浪跡天涯',
        sex:'男',
        age:''
    },
    {
        id:5,
        name:'守候',
        sex:'',
        age:''
    },
    {
        id:3,
        name:'鴻雁',
        sex:'',
        age:'20'
    }
];
//根據id去重和設置'--'
students=ec(students).unique().setInfo().end();
console.log(students)
複製代碼

結果仍是同樣,只是增長了一個方法,方便鏈式調用。

關於實現鏈式調用,這個確定是會增長代碼的,若是調用的方法並非一些經常使用,通用的方法的話,只是處理一些特殊格式的數據的方法(如上實例),不建議花費時間,實現鏈式調用,普通調用就好。若是是一些經常使用的函數的封裝,就建議使用鏈式調用。

4.違反單一職責原則

在上面的實例裏面,相信你們都看到了,遵照單一職責的好處,可是單一職責也有缺點,就是會增長代碼的複雜程度。

在市面上,也有API是違反單一職責的。

JQuery 的 html() 方法,既能夠獲取 innerHTML ,也能夠設置 innerHTML 。 attr ()既能夠獲取 DOM 元素的某一個屬性,也能夠設置 DOM 元素的某一個屬性。

在維護上面,這樣的代碼,可能會給維護增長難度,可是對於使用者而言,這樣簡化了使用。這應該是一個取捨關係,取什麼,舍什麼。這個就是具體狀況具體分析。

5.小結

今天的例子就到這裏了,這個例子,解釋降解函數單一原則會有什麼好處。這個例子比上篇文章的例子還要簡單。你們看不明白,把代碼拷貝在瀏覽器上運行,就很好理解。若是你們對這個例子有什麼更好的建議,或者代碼上有什麼問題,歡迎在評論區留言,你們多交流,相互學習。

---------------------華麗的分割線---------------------

想了解更多,關注關注個人微信公衆號:守候書閣

相關文章
相關標籤/搜索