1.前言
上篇文章寫了新增擴充套件性方面的重構,講到了開放封閉原則。學習的步伐不能就此停止,今天的文章,將會提及開發的另一個原則:單一職責原則。通俗點說就是一個函式只做一件事,下面將會通過幾個例項,探究單一職責原則。
2.單一職責表現形式
單一職責的定義可以理解為:一個物件或者方法,只做一件事。
遵守單一職責的例項太多了,下面簡單列舉一下。
原生的API方面
trimRight()和trimLeft():trimRight 只負責去除右邊的空白,其它地方一概不管。 trimLeft 只負責去除右邊的空白,其它地方也一概不關。
concat(): concat 只負責連線兩個或更多的陣列,並返回結果。不會涉及刪除陣列的操作。
toFixed(): toFixed 只把 Number 型別的值四捨五入為指定小數位數的數字。不會執行其它操作。
JQuery 的 API
$.each() 只負責遍歷,要處理什麼,自己再動手操作。
css() 只負責設定 DOM 的 style ,不會設定 innerHTML 。
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.小結
今天的例子就到這裡了,這個例子,解釋降解函式單一原則會有什麼好處。這個例子比上篇文章的例子還要簡單。大家看不明白,把程式碼拷貝在瀏覽器上執行,就很好理解。如果大家對這個例子有什麼更好的建議,或者程式碼上有什麼問題,歡迎在評論區留言,大家多交流,相互學習。
---------------------華麗的分割線---------------------
想了解更多,關注關注我的微信公眾號:守候書閣