重构 - 保持函数的单一职责

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.小结

今天的例子就到这里了,这个例子,解释降解函数单一原则会有什么好处。这个例子比上篇文章的例子还要简单。你们看不明白,把代码拷贝在浏览器上运行,就很好理解。若是你们对这个例子有什么更好的建议,或者代码上有什么问题,欢迎在评论区留言,你们多交流,相互学习。

---------------------华丽的分割线---------------------

想了解更多,关注关注个人微信公众号:守候书阁

相关文章
相关标签/搜索