日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
重構(gòu),有品位的代碼之重構(gòu)API

本文轉(zhuǎn)載自微信公眾號「前端萬有引力」,作者 一川 。轉(zhuǎn)載本文請聯(lián)系前端萬有引力公眾號。

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項目有:域名申請、雅安服務(wù)器托管、營銷軟件、網(wǎng)站建設(shè)、岢嵐網(wǎng)站維護、網(wǎng)站推廣。

寫在前面

伙伴們,最近事情有點多、空余時間都花在學(xué)習(xí)新知識、新技術(shù)以及鞏固基礎(chǔ)上了,在實踐開發(fā)越來越覺得自己的技術(shù)和能力有限,認識到了自己的短板和不足。后面我會把自己所學(xué)所看,以及在項目實踐中對方法進行總結(jié),分享給各位伙伴們共同學(xué)習(xí)、批評指正。

今天就繼續(xù)分享《重構(gòu),有品味的代碼》系列第八篇文章,As you know,模塊和函數(shù)組成了軟件的鋼筋水泥,而api就是整個軟件建筑的棟和梁。顯而易見,在對軟件開發(fā)有了深層次的理解,我們會發(fā)現(xiàn)如何改進api將更新數(shù)據(jù)的函數(shù)和讀取數(shù)據(jù)的函數(shù)進行分割。讓每個函數(shù)都做自己的本分,銜接它們之間的事情交給模塊去調(diào)用。

重構(gòu)API

常見的重構(gòu)API的方法有:

  • 將查詢函數(shù)和修改函數(shù)分離
  • 函數(shù)參數(shù)化
  • 移除標(biāo)記參數(shù)
  • 保證完整性
  • 以查詢?nèi)〈鷧?shù)
  • 以參數(shù)取代查詢
  • 移除設(shè)值函數(shù)
  • 以工廠函數(shù)取代構(gòu)造函數(shù)
  • 以命令取代函數(shù)
  • 以函數(shù)取代命令

1. 將查詢函數(shù)和修改函數(shù)分離

如果函數(shù)只是作為取值函數(shù),沒有其他多余的實現(xiàn)功能,那么這個函數(shù)是很單純的、很有價值的東西。因為可以任意調(diào)用此函數(shù),可以在整個項目的任意角落使用,無需擔(dān)心有其它多余的累贅。記?。喝魏斡蟹祷刂档暮瘮?shù),不應(yīng)該有其它多余的功能,即命令和查詢分開。

通常做法是:拷貝整個函數(shù)將其作為一個查詢來命名,在新建的此查詢函數(shù)中移除所有有附加功能的語句,并對其進行檢查原函數(shù)的所有調(diào)用處。如果調(diào)用處使用了該函數(shù)的返回值,就將其改為調(diào)用新建的查詢函數(shù),并在下面立刻進行一次調(diào)用,且從原函數(shù)中移除返回值。

舉個栗子

 
 
 
  1. //原始寫法
  2. const setOk = ()=>{...}
  3. const selectPeopleFun = (people)=>{
  4.   for(let p in people){
  5.     if(p === "yichuan"){
  6.       setOk();
  7.       return "good";
  8.     }
  9.     if(p === "onechuan"){
  10.       setOk();
  11.       return "ok";
  12.     }
  13.     return "";
  14.   }
  15. }
  16. //重構(gòu)寫法
  17. const setOk = ()=>{...}
  18. const findNull = (people)=>{
  19.   for(const p of people){
  20.     if(p === "yichuan"){
  21.       setOk();
  22.       return;
  23.     }
  24.     if(p === "onechuan"){
  25.       setOk();
  26.       return;
  27.     }
  28.   }
  29.   return;
  30. }
  31. const selectPeopleFun = (people)=>{
  32.   if(findNull(people) !== "") setOk();
  33. }

2. 函數(shù)參數(shù)化

當(dāng)我們發(fā)現(xiàn)兩個函數(shù)的邏輯非常相似,只有某些字面量值不同時,可以將其進行抽取合并成一個函數(shù),以參數(shù)的形式傳入不同的值,從而消除重復(fù)的邏輯。此重構(gòu)方法能夠使得邏輯更加簡潔、復(fù)用性強,因為每個函數(shù)都可以進行多次使用。

舉個栗子

 
 
 
  1. //原始邏輯
  2. function useFun(param){...}
  3. function baseFunction(param){
  4.   if(param < 0) return useFun(param);
  5.   const amount = bottomFun(param) * 0.1 + middleFun(param) * 0.2 + topFun(param) *0.3;
  6.   return useFun(amount);
  7. }
  8. function bottomFun(param){
  9.   return Math.min(param,100)
  10. }
  11. function middleFun(param){
  12.   return param > 100 ? Math.min(param,200) - 100 :0;
  13. }
  14. function topFun(param){
  15.   return param > 200 ? param - 200 : 0;
  16. }
  17. //重構(gòu)代碼
  18. function commonFun(param,bottom,top){
  19.   return param > bottom ? Math.min(param,top) - bottom:0;
  20. }
  21. function baseFun(param){
  22.   if(param<0) return useFun(0);
  23.   const amount = commonFun(param,0,100) * 0.1 + commonFun(param,100,200) * 0.2 + commonFun(param,200,Infinity) *0.3;
  24.   return useFun(amount);
  25. }

3. 移除標(biāo)記參數(shù)

標(biāo)記參數(shù)直接理解就是作為標(biāo)記的參數(shù),即通常調(diào)用者用其來只是被調(diào)用函數(shù)應(yīng)該執(zhí)行哪部分邏輯。但事與愿違,標(biāo)記參數(shù)在實際使用過程中并沒達到作為標(biāo)記的作用,令人難以理解到底哪部分函數(shù)可以調(diào)用、應(yīng)該如何調(diào)用。通常我們通過API查看哪部分是可調(diào)用函數(shù),但是編輯參數(shù)卻會進行隱藏函數(shù)調(diào)用中存在的差異性,在使用這些函數(shù)我們還得閱讀上下文中標(biāo)記參數(shù)有哪些可用的值。

要知道布爾值作為標(biāo)記是多么荒唐的使用方法,因為其不能見名知意的傳遞信息,在函數(shù)調(diào)用時很難厘清true代表的含義,但是明確使用函數(shù)完成單獨的任務(wù),就顯得清晰的多。

當(dāng)然并非所有的類似參數(shù)都是標(biāo)記參數(shù),如果調(diào)用者傳入的程序中不斷傳遞的數(shù)據(jù),那么這樣的參數(shù)就不叫做標(biāo)記參數(shù)。只有當(dāng)調(diào)用者初入字面量值時,或者在函數(shù)內(nèi)部只有參數(shù)影響了函數(shù)內(nèi)部的控制流,此時作為參數(shù)就是標(biāo)記參數(shù)。

移除標(biāo)記參數(shù)不僅使得代碼更加整潔,并且能夠幫助開發(fā)工具更好的發(fā)揮作用。去掉標(biāo)記參數(shù)后,代碼分析工具能夠更清晰體現(xiàn)“高級”和“普通”邏輯在使用時的區(qū)別。如果某個函數(shù)有多個標(biāo)記參數(shù),此時想要移除得花費功夫,得不償失還不如將其保留,但是也側(cè)面證明此函數(shù)做的太多,需要將其邏輯進行簡化。

舉個栗子

 
 
 
  1. //原始代碼
  2. function setFun(name,value){
  3.   if(name === "height"){
  4.     this._height = value;
  5.     return;
  6.   }
  7.   if(name === "width"){
  8.     this._width = value;
  9.     return;
  10.   }
  11. }
  12. //重構(gòu)代碼
  13. function setHeight(value){
  14.   this._height = value;
  15. }
  16. function setWidth(value){
  17.   this._width = value;
  18. }

4. 保證完整性

當(dāng)看到代碼從一個記錄結(jié)構(gòu)中導(dǎo)出幾個值,然后又把這幾個值傳遞給一個函數(shù),那么可以把整個記錄傳遞給這個函數(shù),在函數(shù)內(nèi)部導(dǎo)出所需要的值。

 
 
 
  1. //原始代碼
  2. const low = aRoom.dayRange.low;
  3. const high = aRoom.dayRange.high;
  4. if(plan.goodRange(low,high)){...}
  5. //重構(gòu)代碼
  6. if(plan.goodRange(aRoom.dayRange)){...}

5. 以查詢?nèi)〈鷧?shù)

函數(shù)的參數(shù)列表應(yīng)該總結(jié)該函數(shù)的可變性,標(biāo)識出函數(shù)可能體現(xiàn)出行為差異的主要方式,但是參數(shù)列表又應(yīng)該盡量避免冗余,因為短小精悍易理解。什么是冗余,就是倘若調(diào)用函數(shù)中傳入一個值,而這個值由函數(shù)自己獲取,這個本不必要的參數(shù)會增加調(diào)用者的難度,因為調(diào)用者不得不去找出此參數(shù)定義的位置。

如果想要移除得參數(shù)值只需要向另一個參數(shù)值查詢即可得到,這就可以使用以查詢代替參數(shù);如果在處理的函數(shù)具有引用透明性,即在任何時候只要傳入相同的參數(shù)值,該函數(shù)的行為永遠一致,可以讓它訪問一個全局變量。

6. 以參數(shù)取代查詢

在瀏覽函數(shù)實現(xiàn)時,會經(jīng)常發(fā)現(xiàn)一些糟糕的引用關(guān)系,比如引用一些全局變量或者另一個想要移除得元素,其實可以通過將其替換成函數(shù)參數(shù)來解決,將處理引用關(guān)系的責(zé)任推卸給函數(shù)調(diào)用者。其實此重構(gòu)思想是:改變代碼的依賴關(guān)系,讓目標(biāo)函數(shù)不再依賴某個元素,將元素的值以參數(shù)形式進行傳遞給函數(shù)。當(dāng)然,如果把所有依賴關(guān)系都變成參數(shù),會導(dǎo)致參數(shù)列表冗長重復(fù),其次倘若作用域間的共享太多,會導(dǎo)致函數(shù)間過度依賴。

具體做法:將執(zhí)行查詢操作的代碼進行變量提煉,將其從函數(shù)體中分離,對現(xiàn)有函數(shù)體代碼不再執(zhí)行查詢操作,而是使用上一步提煉的變量,對此部分代碼使用函數(shù)提煉。使用內(nèi)聯(lián)變量就是把提煉出來的變量放到一個函數(shù)中,且對原先的函數(shù)使用內(nèi)聯(lián)函數(shù)。

 
 
 
  1. targetFun(plan)
  2. const otherFun = {...}
  3. function targetFun(plan){
  4.   curPlan =  otherFun.curPlan
  5.   ...
  6. }
  7. //重構(gòu)
  8. targetFun(plan)
  9. function targetFun(plan,curPlan){
  10.   ...
  11. }

7. 移除設(shè)值函數(shù)

當(dāng)為某個字段提供了設(shè)置函數(shù),表示此字段被改變,如果不希望在對象創(chuàng)建之后字段被改變,就不要提供設(shè)值函數(shù),同時聲明此字段不可改變。但是呢,有些開發(fā)者喜歡通過訪問函數(shù)來讀取字段值,在構(gòu)造函數(shù)內(nèi)也是,這就會導(dǎo)致構(gòu)造函數(shù)成為設(shè)值函數(shù)的唯一使用者,就這樣你還不如直接移除設(shè)值函數(shù)呢,沒有意義。

當(dāng)然,對象有可能是由客戶端通過腳本(通過調(diào)用構(gòu)造函數(shù),即一系列的設(shè)置函數(shù))進行構(gòu)造出來的,而不是只有一次簡單的構(gòu)造函數(shù)調(diào)用。在執(zhí)行完創(chuàng)建腳本后,此新生對象的部分字段不應(yīng)該再被修改,設(shè)值函數(shù)只能被允許在起初對象創(chuàng)建過程中被調(diào)用。其實此時也應(yīng)該移除設(shè)值函數(shù),能夠更加清晰的表達意圖。

 
 
 
  1. class User{
  2.   get(){...}
  3.   set(){...}
  4. }
  5. //重構(gòu)
  6. class User{
  7.   get(){...}
  8. }

8. 以工廠函數(shù)取代構(gòu)造函數(shù)

很多面向?qū)ο笳Z言都有構(gòu)造函數(shù)用于對象的初始化,通常客戶端會通過調(diào)用構(gòu)造函數(shù)來新建對象。但對于普通函數(shù)而言,構(gòu)造函數(shù)具有一定的局限性,通常只能返回當(dāng)前所調(diào)用類的實例,就是無法根據(jù)環(huán)境或參數(shù)信息返回子類實例或代理對象。且構(gòu)造函數(shù)名字是固定的,因此無法使用比默認名字更清晰的函數(shù)名,此外還需要通過特殊的操作符(關(guān)鍵字new)來創(chuàng)建實例調(diào)用。然而,工廠函數(shù)就不受限制,可以實現(xiàn)內(nèi)部調(diào)用構(gòu)造函數(shù),也可以使用其他方式調(diào)用。

9. 以命令取代函數(shù)

函數(shù)可以是作為獨立函數(shù),也可以作為類對象中的方法,還是作為程序設(shè)計的基本構(gòu)造模塊。將函數(shù)封裝成自己的對象成為命令對象,當(dāng)然這種對象大多只服務(wù)于單一函數(shù),獲得該函數(shù)的請求并進行執(zhí)行函數(shù),就是這種對象存在的意義。

與普通函數(shù)相比,命令對象提供了更加強大的控制靈活性和更強的表達能力,除了函數(shù)調(diào)用本身,命令對象還可以作為支持附加的操作,比如撤銷??梢酝ㄟ^命令對象提供的方法進行設(shè)置和取值操作,從而提升豐富的生命周期管理能力。

具體方法:為想要包裝的函數(shù)創(chuàng)建一個空類,并根據(jù)該函數(shù)的名字命名類,將函數(shù)搬移到空類中,并對每個參數(shù)創(chuàng)建一個字段,在構(gòu)造函數(shù)中添加對應(yīng)的參數(shù)。

舉個栗子

 
 
 
  1. //原始代碼
  2. function user(name,work,address){
  3.   let result = "";
  4.   let addressLevel ="";
  5.   ...long code
  6. }
  7. //重構(gòu)代碼
  8. class User{
  9.   constructor(name,work,address){
  10.     this._name = name;
  11.     this._work = work;
  12.     this._addrsss = address;
  13.   }
  14.   clac(){
  15.     this._result="";
  16.     this._addressLevel ="";
  17.     ...long code
  18.   }
  19. }

10. 以函數(shù)取代命令

命令對象為處理復(fù)雜計算提供了強大的機制,可以輕松將原本復(fù)雜的函數(shù)拆分成多個方法,彼此之間通過字段進行狀態(tài)共享。拆分后的方法可以分別進行調(diào)用,開始調(diào)用之前的數(shù)據(jù)狀態(tài)也可以逐步構(gòu)建,但是這種強大功能是有代價的。通常我們調(diào)用函數(shù)讓其完成自身的任務(wù),當(dāng)此函數(shù)不是很復(fù)雜時,命令對象顯得得不償失,還不如使用普通函數(shù)呢。

通常的,將創(chuàng)建并執(zhí)行命令對象的代碼單獨提煉到獨立函數(shù)中,對命令對象在執(zhí)行階段用到的函數(shù)逐一使用內(nèi)聯(lián)函數(shù)。使用改變函數(shù)聲明,將構(gòu)造函數(shù)的參數(shù)轉(zhuǎn)移到執(zhí)行函數(shù)。對于所有的字段在執(zhí)行函數(shù)中找到引用它的地方,并將其改為使用參數(shù),將調(diào)用構(gòu)造函數(shù)和調(diào)用執(zhí)行函數(shù)兩步進行內(nèi)聯(lián)到調(diào)用函數(shù)中。

舉個栗子

 
 
 
  1. //原始代碼
  2. class ChargeClass{
  3.   constructor(custom,param){
  4.     this._custom = custom;
  5.     this._param = param;
  6.   }
  7.   clac(){
  8.     return this._custom.rate * this._param
  9.   }
  10. }
  11. //重構(gòu)代碼
  12. function charge(custom,param){
  13.   return custom.rate * param;
  14. }

網(wǎng)頁標(biāo)題:重構(gòu),有品位的代碼之重構(gòu)API
分享網(wǎng)址:http://www.5511xx.com/article/cojchgo.html