Reconstruction-preservation function's single responsibility

Posted by teddmcload on Wed, 25 Sep 2019 16:51:50 +0200

1. Preface

In the last article, I wrote about refactoring to add extensibility, and I talked about the principle of openness and closeness. The pace of learning can not stop here. Today's article will refer to another principle of development: the principle of single responsibility. Popularly speaking, a function only does one thing. Here we will explore the single responsibility principle through several examples.

2. Single duty manifestation

The definition of a single responsibility can be understood as: an object or method, doing only one thing.

There are too many examples of compliance with a single responsibility. Here's a brief list.

Native API aspects

trimRight() and trimLeft(): trimRight is only responsible for removing the right margin, regardless of the rest. TrimLeft is only responsible for removing the right margin, and nothing else.

concat(): concat is only responsible for connecting two or more arrays and returning results. It does not involve deleting arrays.

toFixed(): toFixed rounds only Number-type values to specified decimal digits. No other operations will be performed.

JQuery's API

each() is only responsible for traversal, what to deal with, and do it yourself.

css() is only responsible for setting the style of DOM, not innerHTML.

animate() is only responsible for executing custom animations of CSS attribute sets and does not involve other operations.

Say so, but you may look a little confused, do not see the benefits of adherence to a single principle, let's look at an example.

3. Example-Array Processing

The following examples are given:

There is a batch of information about enrolled students, but the data is duplicated, which needs to be de-duplicated according to id. Then change the empty information to'--'.

let students=[
    {
        id:5,
        name:'Waiting',
        sex:'male',
        age:'',
    },
    {
        id:2,
        name:'Rove all over the world',
        sex:'male',
        age:''
    },
    {
        id:5,
        name:'Waiting',
        sex:'',
        age:''
    },
    {
        id:3,
        name:'Swan goose',
        sex:'',
        age:'20'
    }
];

function handle(arr) {
    //Array weight removal
    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]);
        }
    }
    //Ergodic substitution
    _arr.map(item=>{
        for(let key in item){
            if(item[key]===''){
                item[key]='--';
            }
        }
    });
    return _arr;
}
console.log(handle(students))

The results are all right, but think about it.

1. If we change the requirement, for example, there will be no duplicate records of student information, we need to remove the function of de-duplication, whether it is the whole function, it will also affect the following operations.

2. If the same operation is done in another part of the project, it does not need to be weighted. In this way, we can only write another function which is basically the same, because the above function can not be reused. as follows

function handle1(arr) {
    //Deep copy of array
    let _arr=JSON.parse(JSON.stringify(arr));
    //Ergodic substitution
    _arr.map(item=>{
        for(let key in item){
            if(item[key]===''){
                item[key]='--';
            }
        }
    });
    return _arr;
}

3. If a project has a place, it needs to be sorted by ID. So you still have to write a function, because you can't sort the functions above.

function handle2(arr) {
    //Array weight removal
    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]);
        }
    }
    //Ergodic substitution
    _arr.map(item=>{
        for(let key in item){
            if(item[key]===''){
                item[key]='--';
            }
        }
    });
    //Sort by ID
    _arr.sort((item1,item2)=>item1.id-item2.id);
    return _arr;
}

The problem is that we can't deal with the change of demand flexibly. Functions can hardly be reused.

Here's how to construct it using a single principle

let handle={
    //Array weight removal
    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;
    },
    //Ergodic substitution
    setInfo(arr){
        arr.map(item=>{
            for(let key in item){
                if(item[key]===''){
                    item[key]='--';
                }
            }
        });
        return arr;
    },
    //Sort by id
    sortForId(arr){
        return arr.sort((item1,item2)=>item1.id-item2.id);
    }
};
//Duplicate removal
students=handle.removeRepeat(students);
//set information
students=handle.setInfo(students);
console.log(students);

The result is the same, and in this way, the method can be combined, more flexible and easy to reuse.

If you also need to sort by ID, just add a line of code based on the results of the above code execution.

//Sort by ID
students=handle.sortForId(students);
console.log(students);

If the original data does not need to be de-duplicated, after setting up the information, sort it directly

let students=[
    {
        id:5,
        name:'Waiting',
        sex:'male',
        age:'',
    },
    {
        id:2,
        name:'Rove all over the world',
        sex:'male',
        age:''
    },
    {
        id:5,
        name:'Waiting',
        sex:'',
        age:''
    },
    {
        id:3,
        name:'Swan goose',
        sex:'',
        age:'20'
    }
];
//set information
students=handle.setInfo(students);
//Sort by ID
students=handle.sortForId(students);

In this way, the functions can be flexibly combined and reused in a controllable range even if the requirements are changed in the future.

If you find it difficult to assign students continuously, you can learn from JQuery's chain invocation method.

let ec=(function () {
    let handle=function (obj) {
        this.obj=JSON.parse(JSON.stringify(obj));
    };
    handle.prototype={
        /**
         * @description Duplicate removal
         */
        unique(){
            //De-duplication based on id array
            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 Setting up Secret Information
         */
        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 processing results
         * @return {Array|*}
         */
        end(){
            return this.obj;
        }
    }
    //Exposure constructor interface
    return function (obj) {
        return new handle(obj);
    }
})();
let students=[
    {
        id:5,
        name:'Waiting',
        sex:'male',
        age:'',
    },
    {
        id:2,
        name:'Rove all over the world',
        sex:'male',
        age:''
    },
    {
        id:5,
        name:'Waiting',
        sex:'',
        age:''
    },
    {
        id:3,
        name:'Swan goose',
        sex:'',
        age:'20'
    }
];
//Deploy id to reset and set'--'
students=ec(students).unique().setInfo().end();
console.log(students)

The result is the same, just adding a method to facilitate chain invocation.

As for the implementation of chain invocation, this is bound to add code. If the method invoked is not some common and general method, it is only a method to process some special format data (such as the example above). It is not recommended to spend time to implement chain invocation, just ordinary invocation. If it is encapsulation of some commonly used functions, it is recommended to use chain invocation.

4. Violation of the Single Responsibility Principle

In the above example, I believe that we all see the benefits of complying with a single responsibility, but there are also disadvantages of a single responsibility, which is to increase the complexity of the code.

On the market, there are API s that violate a single responsibility.

JQuery's html() method can either get innerHTML or set innerHTML. attr () can either acquire an attribute of a DOM element or set an attribute of a DOM element.

In maintenance, such code may make maintenance more difficult, but for users, it simplifies the use. This should be a trade-off relationship, what to choose and what to give up. This is a concrete analysis of the specific situation.

5. summary

That's all for today's example, which explains the benefits of the single principle of degradation functions. This example is simpler than the one in the previous article. You can't understand it. If you run the code copy on the browser, you will understand it very well. If you have any better suggestions for this example, or if you have any problems with the code, please leave a message in the comment area. You can communicate with each other and learn from each other.

----------------------------------- gorgeous partition line-----------------------------------------------------------------------------------------------------

For more information, pay attention to my Wechat Public Number: Waiting for the Bookshop

Topics: Front-end JSON Attribute JQuery REST