摘要:下面就通過一個簡單的例子,怎么讓更加的實用,更好的復用。代碼的實用性,只能盡量,盡量再盡量。關于實用性,命名和擴展性也很重要。而且,這樣沒復用性。關于這篇文章,也是我目前嘗試的一種方式,如果大家有更好的一個實現方式,歡迎在評論區留言。
程序員的精神,不應不止于實現,更要注重優化。不應止于表面,更要研究內部機制,方能青出于藍而勝于藍。1.前言
在上家公司開發后臺管理系統的時候,頻繁要處理各種數據顯示的問題,一開始是實現就好。后來寫多了,自己看得也難受了。就想著怎么優化代碼和復用了。下面就通過一個簡單的例子,怎么讓 API 更加的實用,更好的復用。
1.代碼的實用性,只能盡量,盡量再盡量。不會出現完美的API,或者是一次編寫,永不修改的 API 。2.舉個例子2.關于實用性,API 命名和擴展性也很重要。但之前寫過文章,在這里就不重復了。[[前端開發]--分享個人習慣的命名方式](https://juejin.im/post/5b6ad6...,重構 - 設計API的擴展機制
比如有一個需求,有這樣的數據
{ cashAmount: 236700,//回款金額(分) cashDate: "2018-05-26 10:25:28",//回款時間 cashId: "SM2018022800020692",//回款ID cashStatus: 0,//回款狀態 createTime: "2018-05-23 10:26:25",//創建時間 custoName: "廣州測試有限公司",//回款公司名稱 id: "SM2018022800020692",//回款ID merchandisers: "守候",//回款公司聯系人 ordId: "SO2018022800020692",//訂單ID payChannel: null,//支付方式 remark: "",//備注 userMobile: "18819222363",//回款公司聯系人電話 }
需要對數據進行以下處理,再渲染到頁面
1.cashAmount 轉換成元,并保留兩位小數
2.cashStatus 進行解析(0-未回款 1-已回款)
3.payChannel 進行解析 ("zfb"-支付寶,"wx"-微信支付,"cash"-現金支付,"bankTransfer"-銀行轉賬)
4.所有值為 "" , null , undefined 的字段,全部設置為:"--"
面對這樣的需要,很簡單,順手就來
let obj = { cashAmount: 236700,//回款金額(分) cashDate: "2018-05-26 10:25:28",//回款時間 cashId: "SM2018022800020692",//回款ID cashStatus: 0,//回款狀態 createTime: "2018-05-23 10:26:25",//創建時間 custoName: "廣州測試有限公司",//回款公司名稱 id: "SM2018022800020692",//回款ID merchandisers: "守候",//回款公司聯系人 ordId: "SO2018022800020692",//訂單ID payChannel: null,//支付方式 remark: "",//備注 userMobile: "13226452474",//回款公司聯系人電話 } function setValue(obj) { let _obj=JSON.parse(JSON.stringify(obj)); //設置金額 _obj.cashAmount = (_obj.cashAmount / 100).toFixed(2); //解析回款狀態 _obj.cashStatus = _obj.cashStatus === 0 ? "未回款" : "已回款"; //解析支付方式 let payChannelLabel = { "zfb": "支付寶", "wx": "微信支付", "cash": "現金支付", "bankTransfer": "銀行轉賬" } _obj.payChannel=payChannelLabel[_obj.payChannel]; //設置默認值 for (let key in _obj){ if(_obj[key]===""||_obj[key]===null||_obj[key]===undefined){ _obj[key]="--" } } return _obj; } obj=setValue(obj); console.log(obj)
結果也正確,如下圖
但是如果以后需求變了,比如 userMobile 要改成 xxx xxx xxxx 這種展示方式呢?
也很簡單,修改下
function setValue(obj) { let _obj=JSON.parse(JSON.stringify(obj)); //設置金額 //解析回款狀態 //解析支付方式 /*和上面代碼一樣,不重復粘貼*/ //設置電話號碼格式 let _formatType="xxx xxx xxxx",i = 0; _obj.userMobile= _formatType.replace(/x/g, function(){ return _obj.userMobile[i++] }); //設置默認值 /*和上面代碼一樣,不重復粘貼*/ }
代碼寫好了,想必大家也開始難受了。因為每改一次需求,就要改一次 setValue 。改的多了,出現問題的概率就大了。而且,這樣沒復用性。試想,如果別的頁面有一個需求,同樣的數據。但是 cashDate 字段只需要精確到時分秒。這樣的需求,大同小異。但上面的代碼不適用,需要拷貝一個 setValue 方法(就叫 setValue2 吧),然后添加 cashDate 只顯示 時分秒的邏輯。代碼很好寫
function setValue2(obj) { let _obj=JSON.parse(JSON.stringify(obj)); //設置金額 //解析回款狀態 //解析支付方式 //設置電話號碼格式 /*和上面代碼一樣,不重復粘貼*/ //設置 cashDate 只顯示時分秒 _obj.cashDate= _obj.cashDate.split(" ")[0]; //設置默認值 /*和上面代碼一樣,不重復粘貼*/ }3.單一職責原則
想必大家更難受了,因為沒發復用,導致出現了幾乎完全一樣的函數。這個問題解決方式很多,先說下第一個,也是一個 API 設計原則--單一職責原則。
顧名思義,單一職責原則就是讓每一個函數只做一件事。下面把代碼改造下
/** * @description 設置默認值 * @param obj 待處理對象 * @return obj 已處理對象 */ function setDefault(obj) { let _obj=JSON.parse(JSON.stringify(obj)); for (let key in _obj){ if(_obj[key]===""||_obj[key]===null||_obj[key]===undefined){ _obj[key]="--" } } return _obj; } /** * @description 格式化電話號碼 * @param obj 待處理對象 * @return obj 已處理對象 */ function setFormatMobile(obj) { let _obj=JSON.parse(JSON.stringify(obj)); let _formatType="xxx xxx xxxx",i = 0; _obj.userMobile= _formatType.replace(/x/g, function(){ return _obj.userMobile[i++] }); return _obj; } /** * @description 解析支付方式 * @param obj 待處理對象 * @return obj 已處理對象 */ function setPayChannelLabel(obj) { let _obj=JSON.parse(JSON.stringify(obj)); let payChannelLabel = { "zfb": "支付寶", "wx": "微信支付", "cash": "現金支付", "bankTransfer": "銀行轉賬" } _obj.payChannel = payChannelLabel[_obj.payChannel]; return _obj; } /** * @description 設置回款金額 * @param obj 待處理對象 * @return obj 已處理對象 */ function setCashAmount(obj) { let _obj=JSON.parse(JSON.stringify(obj)); _obj.cashAmount = (_obj.cashAmount / 100).toFixed(2); return _obj; } /** * @description 解析回款狀態 * @param obj 待處理對象 * @return obj 已處理對象 */ function setCashStatus(obj) { let _obj=JSON.parse(JSON.stringify(obj)); _obj.cashStatus = _obj.cashStatus === 0 ? "未回款" : "已回款"; return _obj; } obj=setFormatMobile(obj); obj=setCashStatus(obj); obj=setCashAmount(obj); obj=setPayChannelLabel(obj); obj=setDefault(obj);
結果一樣,如果需要加上 cashDate 只顯示 時分秒。加上邏輯就行了
/** * @description 設置匯款時間 * @param obj 待處理對象 * @return obj 已處理對象 */ function setCashDate(obj) { let _obj=JSON.parse(JSON.stringify(obj)); _obj.cashDate = _obj.cashDate.split(" ")[0]; return _obj; } obj=setFormatMobile(obj); obj=setCashStatus(obj); obj=setCashAmount(obj); obj=setCashDate(obj); obj=setPayChannelLabel(obj); obj=setDefault(obj); console.log(obj)
讓 API 保持單一原則的好處是,復用性比復雜的 API 更好,而且編寫的難度更低。
4.最少知識原則上面的寫法雖然實現了復用,看著比之前好了一點,但是看著也是難受,畢竟賦值了幾次,而且還有那么多的全局函數。
首先,全局函數這個容易解決,用一個對象包裹起來,全局函數少了,也方便管理。
重復的代碼和注釋,這里忽略,不重復粘貼
let handle={ setDefault(obj) { //省略的代碼 }, setFormatMobile(obj) { //省略的代碼 }, setPayChannelLabel(obj) { //省略的代碼 }, setCashAmount(obj) { //省略的代碼 }, setCashStatus(obj) { //省略的代碼 } } obj=handle.setFormatMobile(obj); obj=handle.setCashStatus(obj); obj=handle.setCashAmount(obj); obj=handle.setPayChannelLabel(obj); obj=handle.setDefault(obj); console.log(obj)
第二個讓人難受的地方就是一個步驟,經過了幾次的賦值,這個難免有點難受,寫起來也麻煩,記憶成本高。解決起來也很簡單,就是另寫一個函數,把那些操作步驟封裝在一起就行了。封裝的目的就是為了讓使用的人,只需要記住一個函數的使用方式就可以了,不需要記住多個函數的使用方式。
let handle={ /*省略代碼*/ setCash(obj){ let _obj=JSON.parse(JSON.stringify(obj)); _obj=this.setFormatMobile(_obj); _obj=this.setCashStatus(_obj); _obj=this.setCashAmount(_obj); _obj=this.setPayChannelLabel(_obj); _obj=this.setDefault(_obj); return _obj; } } obj=handle.setCash(obj); console.log(obj)5.配置數據和業務邏輯分離
上面的代碼,看著算是比較舒服了,但是問題還是有,就是 setCash 函數寫得太死了。固定了五個方法 :setFormatMobile,setCashStatus,setCashAmount,setPayChannelLabel,setDefault 。如果以后不需要處理電話號碼,又要改 setCash ,把 _obj=this.setFormatMobile(_obj); 這行代碼去掉。雖然改動也很小,但是問題就出來了。如果其中一個地方需要執行 setFormatMobile ,就不能刪除。如果另一個地方, 不需要執行 setFormatMobile ,就要刪除。這樣子就顧此失彼了。
解決的方案想必大家也知道了,就是需要執行什么函數,就在函數上動態傳入。
let handle={ /*省略代碼*/ setCash(obj,fns="setFormatMobile,setCashStatus,setCashAmount,setPayChannelLabel,setDefault"){ let _obj=JSON.parse(JSON.stringify(obj)); let _fns=fns.split(","); _fns.forEach(item => { _obj=this[item](_obj); }); return _obj; } } obj=handle.setCash(obj); console.log(obj) //比如另一個地方不需要執行 setFormatMobile obj = { cashAmount: 236700,//回款金額(分) cashDate: "2018-05-26 10:25:28",//回款時間 cashId: "SM2018022800020692",//回款ID cashStatus: 0,//回款狀態 createTime: "2018-05-23 10:26:25",//創建時間 custoName: "廣州測試有限公司",//回款公司名稱 id: "SM2018022800020692",//回款ID merchandisers: "守候",//回款公司聯系人 ordId: "SO2018022800020692",//訂單ID payChannel: null,//支付方式 remark: "",//備注 userMobile: "13226452474",//回款公司聯系人電話 } obj=handle.setCash(obj,"setCashStatus,setCashAmount,setPayChannelLabel,setDefault"); console.log("比如另一個地方不需要執行 setFormatMobile",obj)6.批量處理
看到這里,好像差不多了。但是寫下去,大家才會知道,一般的后臺管理系統的用戶列表,數據一般不會只有一條。一般而言是一個數組對象。如下
let arr=[ { cashAmount: 236700,//回款金額(分) cashDate: "2018-05-26 10:25:28",//回款時間 cashId: "SM2018022800020692",//回款ID cashStatus: 0,//回款狀態 createTime: "2018-05-23 10:26:25",//創建時間 custoName: "廣州測試有限公司",//回款公司名稱 id: "SM2018022800020692",//回款ID merchandisers: "守候",//回款公司聯系人 ordId: "SO2018022800020692",//訂單ID payChannel: null,//支付方式 remark: "",//備注 userMobile: "13226452474",//回款公司聯系人電話 }, {/*省略的代碼*/}, {/*省略的代碼*/}, {/*省略的代碼*/}, //省略的代碼 ]
寫起來的時候呢,要這樣寫
arr.forEach((item,index)=>{ arr[index]=handle.setCash(item); }) console.log(arr)
雖然代碼不多,但是有更好的方案,就用更好的方案。比如使用批量處理的方式。就多寫一個函數就行了。
let handle={ /*省略代碼*/ batch(arr,fns,...orther){ let _arr=JSON.parse(JSON.stringify(arr)); let _fns=fns.split(","); _arr.forEach((item,index)=>{ _fns.forEach(fn => { _arr[index]=this[fn](_arr[index],...orther); }); }) return _arr } }
調用的時候就比之前簡單了一點,結果也正確
arr=handle.batch(arr,"setCash") console.log(arr)
要傳其他參數也可以
arr=handle.batch(arr,"setCash","setCashStatus,setCashAmount,setPayChannelLabel,setDefault") console.log(arr)
如果要傳入多個操作函數
arr=handle.batch(arr,"setCashStatus,setCashAmount") console.log(arr)7.小結
關于開發上,API 的實用性,暫時就先提這幾個方面,如果以后發現有其他例子,還能從其他方面提高 API 的實用性,就再發文章分享。關于這篇文章,也是我目前嘗試的一種方式,如果大家有更好的一個實現方式,歡迎在評論區留言。
-------------------------華麗的分割線--------------------
想了解更多,和我交流,內推職位,請添加我微信。或者關注我的微信公眾號:守候書閣
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104114.html
摘要:下面就通過一個簡單的例子,怎么讓更加的實用,更好的復用。代碼的實用性,只能盡量,盡量再盡量。關于實用性,命名和擴展性也很重要。而且,這樣沒復用性。關于這篇文章,也是我目前嘗試的一種方式,如果大家有更好的一個實現方式,歡迎在評論區留言。 程序員的精神,不應不止于實現,更要注重優化。不應止于表面,更要研究內部機制,方能青出于藍而勝于藍。 1.前言 在上家公司開發后臺管理系統的時候,頻繁要處理各...
摘要:前言本文給大家分享的題目是基于微服務以及的高可用架構探索與實現。比如說年大地震的時候我正好在東京,當時在做一個金融系統的相關工作。那次大地震導致很多很多的問題,雖然大地震不是在東京發生,但是還是給我們的系統造成了影響。 前言 本文給大家分享的題目是《基于DevOps、微服務以及K8S的高可用架構探索與實現》。整個企業的高可用架構面臨很多的挑戰,面向微服務、容器化以及敏態交付,是我們現在...
摘要:面試如何防騙一份優秀的前端開發工程師簡歷是怎么樣的作為,有哪些一般人我都告訴他,但是他都不聽的忠告如何面試前端工程師 更多資源請Star:https://github.com/maidishike... 文章轉自:https://github.com/jsfront/mo... 3月份前端資源分享 1. Javascript 使用judge.js做信息判斷 javascript...
摘要:業務對賬平臺的核心目的,就是及時發現類似問題,并及時修復。這對對賬平臺的吞吐量造成了挑戰。五健康度對賬中心可以拿到業務系統及其所在整個鏈路的數據一致性信息。在分布式環境下,沒有人能回避數據一致性問題,我們對此充滿著敬畏。 一、引子 根據CAP原理,分布式系統無法在保證了可用性(Availability)和分區容忍性(Partition)之后,繼續保證一致性(Consistency)。我...
閱讀 839·2019-08-30 15:55
閱讀 1413·2019-08-30 13:55
閱讀 1991·2019-08-29 17:13
閱讀 2846·2019-08-29 15:42
閱讀 1336·2019-08-26 14:04
閱讀 1023·2019-08-26 13:31
閱讀 3276·2019-08-26 11:34
閱讀 836·2019-08-23 18:25