<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ?把三千行代碼重構(gòu)為15行!

          共 5435字,需瀏覽 11分鐘

           ·

          2020-10-20 08:05



          • 把三千行代碼重構(gòu)為15行
          • 少用代碼生成器
          • 不要重復(fù)發(fā)明輪子
          • 等你無(wú)法重構(gòu)的時(shí)候再考慮重寫
          • 學(xué)會(huì)單元測(cè)試,培養(yǎng)你的重構(gòu)意識(shí)
          • 所謂重構(gòu)

          如果你認(rèn)為這是一個(gè)標(biāo)題黨,那么我真誠(chéng)的懇請(qǐng)你耐心的把文章的第一部分讀完,然后再下結(jié)論。如果你認(rèn)為能夠戳中您的G點(diǎn),那么請(qǐng)隨手點(diǎn)個(gè)贊。

          把三千行代碼重構(gòu)為15行

          那年我剛畢業(yè),進(jìn)了現(xiàn)在這個(gè)公司。公司是搞數(shù)據(jù)中心環(huán)境監(jiān)控的,里面充斥著嵌入式、精密空調(diào)、總線、RFID的概念,我一個(gè)都不懂。還好,公司之前用Delphi寫的老客戶端因?yàn)樘?,然后就搞了個(gè)Webform的替代,恰好我對(duì)Asp.Net還算了解,我對(duì)業(yè)務(wù)的不了解并不妨礙我稱成為這個(gè)公司的一個(gè)程序員。小公司也有小公司的好,人少,進(jìn)去很快負(fù)責(zé)代碼開發(fā)。我當(dāng)然也就搞這個(gè)數(shù)據(jù)中心智能管理系統(tǒng)啦。

          這個(gè)系統(tǒng)非常的龐大,尤其牛逼的是支持客戶端組態(tài),然后動(dòng)態(tài)生成網(wǎng)頁(yè),數(shù)據(jù)還能通過(guò)Socket實(shí)時(shí)監(jiān)控(那時(shí)我還真就不懂網(wǎng)絡(luò)編程)。這個(gè)對(duì)于當(dāng)時(shí)的我來(lái)說(shuō),真真是高、大、上吶!!當(dāng)時(shí)跟著了解整個(gè)系統(tǒng)大半個(gè)月才算能夠調(diào)試,寫一些簡(jiǎn)單的頁(yè)面。

          在維護(hù)系統(tǒng)的過(guò)程中,時(shí)不時(shí)要擴(kuò)展一些功能,也就接觸了下面這個(gè)類:

          看到?jīng)]有,就是當(dāng)年最最流行的三層架構(gòu)的產(chǎn)物,對(duì)于剛出茅廬的毛頭小子來(lái)說(shuō),這是多么專業(yè)的文件頭注釋,還有反射也就算了,這構(gòu)造函數(shù)還能靜態(tài)的,還能私有的?那時(shí)剛接觸這么高大上的代碼的我,瞬間給跪了!

          但是,類寫多了,我就感覺(jué)越來(lái)越別扭,就是下面這段代碼:

          每增加一個(gè)表,除了要改接口、要改DAL、要改BLL之外,還得在這個(gè)工廠類添加一個(gè)方法,真真是累到手抽筋,即使有當(dāng)時(shí)公司了的G工給我推薦的神器——?jiǎng)榆洿a生成器,這粘貼復(fù)制的幾遍,也是讓我感覺(jué)到異常繁瑣,有時(shí)候打鍵盤稍微累了點(diǎn),還把復(fù)制出來(lái)代碼改錯(cuò)了,你妹的,難道這就是程序員該干的事情,不,絕對(duì)不是!我想起了一句至理名言:當(dāng)你覺(jué)得代碼重復(fù)出現(xiàn)在程序中的時(shí)候,就應(yīng)該重構(gòu)了 。是的,在這句話的指導(dǎo)下,我開始了折騰,決定挑戰(zhàn)這個(gè)高大上的代碼,事實(shí)證明,思想的力量是無(wú)窮的。

          那么,怎么修改呢,仔細(xì)觀察之后,發(fā)現(xiàn)其中className的生成跟返回的類型非常類似,只是一個(gè)是類名,一個(gè)是字符串,這兩者之間應(yīng)該能夠關(guān)聯(lián)起來(lái)。于是google了一下(當(dāng)時(shí)GFW還沒(méi)猖獗起來(lái)哈),隱隱約約就找到了“反射 ”這兩個(gè)字,深入了解之后,確定可以完成。

          接下來(lái),就是返回的類型了,返回的類型并不固定,但是似乎很有規(guī)律……這個(gè)似乎好像在哪里見過(guò),對(duì)了,模板 ,C++課程上有講過(guò)的,于是再次google,了解到了C#中使用了泛型代替了C++中的模板。在學(xué)習(xí)完泛型和反射之后,并參考了網(wǎng)上的一些文章,我搗鼓出了下面的代碼:

          沒(méi)錯(cuò),就是它了,三層架構(gòu)年代最流行的工廠類……

          看著原來(lái)滾十幾屏幕的代碼,變成了十多行的代碼,真是爽到了骨子里去了,太干凈了!唯一讓我擔(dān)憂的是,我進(jìn)公司的時(shí)候,幫忙整理公司申請(qǐng)軟件著作權(quán)都是需要代碼量的,根據(jù)代碼多少行來(lái)評(píng)估軟件的大小,萬(wàn)一老板知道了我非但沒(méi)有幫公司增加代碼量,還減少了,會(huì)不會(huì)立即把我開掉?我沒(méi)敢給我們老板展示我優(yōu)秀的成果,所幸,這段代碼非但沒(méi)有出過(guò)任何問(wèn)題,還避免了以前同事老是在新增一個(gè)類之后,把代碼復(fù)制過(guò)來(lái),但是沒(méi)有正確修改的問(wèn)題,大大提高了效率。雖然,我沒(méi)敢大事宣布我的勞動(dòng)成果,但是這次成功的修改,則徹底讓我走上了代碼重構(gòu)的不歸路。

          看到這里,大家應(yīng)該知道這個(gè)案例是否真實(shí)的了吧。我相信,從08年開始的碼農(nóng)們,看到這種類似的代碼絕對(duì)不比我少。那么,我想告訴你們的是什么呢?

          • 要在編程過(guò)程中多思考
          • 編程的思想很重要,請(qǐng)多看點(diǎn)經(jīng)典的書
          • 從小處著眼,慢慢重構(gòu),尤其在應(yīng)對(duì)一個(gè)大型的系統(tǒng)
          • 當(dāng)重復(fù)出現(xiàn)的時(shí)候,你應(yīng)該考慮重構(gòu)了
          • 粘貼復(fù)制的代碼越少,你的系統(tǒng)越穩(wěn)定

          少用代碼生成器

          我們來(lái)分析一下,為什么我之前的前輩會(huì)寫出上面的代碼。我歸結(jié)起來(lái)有以下幾點(diǎn):

          • 因?yàn)槭褂昧藙?dòng)軟代碼生成器,生成代碼方便,就沒(méi)多想了。
          • 三層架構(gòu)的概念倒是了解了,但是沒(méi)有去深入思考就拿來(lái)應(yīng)用
          • 遇到重復(fù)的代碼,沒(méi)有重構(gòu)的概念,這是思想的問(wèn)題——思想比你的能力重要

          至今為止,還是很多人使用代碼生成器,那么我們應(yīng)該怎么對(duì)待這個(gè)問(wèn)題呢。我認(rèn)為,代碼生成器確實(shí)可以減少你不少工作,但是少用,那些重復(fù)性的工作,除了部分確實(shí)是沒(méi)有辦法的,其他大部分都是可以通過(guò)框架解決的,舉例來(lái)說(shuō),像三層架構(gòu),真正需要用到代碼生成器的,也就是Model類而已,其他的完全可以在框架中完成。因此你要竭盡全力的思考怎么在框架中來(lái)減少你的重復(fù)性工作,而不是依賴于代碼生成器。

          另外,如果你還是在用相關(guān)的代碼生成工具,請(qǐng)重新定義“動(dòng)軟代碼生成器”的代碼模板,自己寫一個(gè)模板 ;或者使用CodeSmith來(lái)完全制定自己的代碼生成 ,因?yàn)閯?dòng)軟給的代碼模板真心亂,比如下面這段代碼:

          for (int n = 0; n < rowsCount; n++)
          {
          model = new DBAccess.Model.eventweek();
          if(dt.Rows[n]["GroupNo"].ToString()!="")
          {
          model.GroupNo=int.Parse(dt.Rows[n]["GroupNo"].ToString());
          }
          if(dt.Rows[n]["Week0"].ToString()!="")
          {
          model.Week0=int.Parse(dt.Rows[n]["Week0"].ToString());
          }
          if(dt.Rows[n]["Week1"].ToString()!="")
          {
          model.Week1=int.Parse(dt.Rows[n]["Week1"].ToString());
          }
          }

          首先,你就不能用 var row=dt.Rows[n] 替代嗎?其次,直接用int.Parse如果拋出了異常性能得有多低?再次,這段代碼要是有點(diǎn)修改,我不是要每個(gè)dt.Rows[n]得改一遍?

          不要重復(fù)發(fā)明輪子

          我們?cè)賮?lái)看看其他的一些代碼:

          public List GetDevices(string dev){
          List devs=new List();

          int start=0;
          for(int i=0;i if(dev[i]=='^'){
          devs.Add(dev.SubString(start,i));
          start=i+1;
          }
          }

          return devs;
          }

          有沒(méi)有很眼熟,沒(méi)錯(cuò),這就是對(duì)String.Split()函數(shù)的簡(jiǎn)單實(shí)現(xiàn)。我的前輩應(yīng)該是從c++程序員轉(zhuǎn)過(guò)來(lái)的,習(xí)慣了各種功能自己實(shí)現(xiàn)一遍,但是他忽略了C#的很多東西。我們不去評(píng)判這段代碼的優(yōu)劣,而實(shí)際上他在很長(zhǎng)一段時(shí)間都運(yùn)行得很好。我們來(lái)看看使用這一段代碼有什么不好的地方:

          • 重復(fù)發(fā)明輪子 ?;ㄙM(fèi)了額外的時(shí)間,函數(shù)的健壯性和很差

          • 可讀性差 。其實(shí)是一個(gè)很簡(jiǎn)單的功能,但是用上了這么一段函數(shù),起初我還以為有什么特別的功能。

          那么,我們應(yīng)該怎樣去避免重復(fù)發(fā)明輪子呢?我從個(gè)人的經(jīng)歷來(lái)提出以下幾點(diǎn),希望能夠?qū)Ω魑挥兴鶐椭?/p>

          • 了解你所學(xué)的編程語(yǔ)言的特性 。你可以看一本基礎(chǔ)的入門書籍,把所有的特性瀏覽一遍,或者上MSDN,把相關(guān)的內(nèi)容過(guò)一遍。

          • 在你決定動(dòng)手發(fā)明一個(gè)輪子之前,先搜索一下現(xiàn)成的解決方案 。你還可以到CodeProject、GitHub之類的網(wǎng)站搜索一下。在知乎上有很多人都在批評(píng)這么一種現(xiàn)象,老是問(wèn)一些重復(fù)性的問(wèn)題,然后又職責(zé)知乎沒(méi)落了,沒(méi)有人回答他的問(wèn)題,實(shí)際上相關(guān)問(wèn)題已經(jīng)有了很詳細(xì)的解答,那提問(wèn)之前,不能首先去搜一下是否有現(xiàn)成的答案,反而指責(zé)沒(méi)有回答他的問(wèn)題呢?

          • 你有一定的基礎(chǔ)之后,還應(yīng)該去讀一下相關(guān)的經(jīng)典書籍,深入了解其中的原理 。比如,你覺(jué)得你有一定的基礎(chǔ)了,我建議你去把《CLR Via C#》多讀幾遍,你了解原理越多,你越是能夠利用這編程語(yǔ)言的特性,從而來(lái)實(shí)現(xiàn)原本那些你認(rèn)為要靠自己寫代碼的功能。

          這里我再舉一個(gè)我自己的例子。在我現(xiàn)有的程序中,我發(fā)現(xiàn)我需要越來(lái)越多的線程來(lái)執(zhí)行一些簡(jiǎn)單的任務(wù),比如在每天檢測(cè)一下硬盤是否達(dá)到90%了,每天9點(diǎn)要控制一下空調(diào)的開啟而在網(wǎng)上6點(diǎn)的時(shí)候把空調(diào)關(guān)掉。線程使用越來(lái)越多,我越是覺(jué)得浪費(fèi),因?yàn)檫@些現(xiàn)場(chǎng)僅僅只需完成一次或者有限的幾次,大部分時(shí)間都是沒(méi)有意義的,那么怎么辦呢?我決定自己寫一個(gè)任務(wù)類,來(lái)完成相關(guān)的事情。說(shuō)干就干,我很快把這個(gè)類寫出來(lái)了。

          public abstract class MissionBase : IMission
          {
          private DateTime _nextExecuteTime;
          protected virtual DateTime[] ExecuteTimePoints { get; private set; }
          protected virtual int IntervalSeconds { get; private set; }
          protected IEngine Engine { get; private set; }

          public bool IsCanceled{get{……}}
          public bool IsExecuting{get{……}}
          public bool IsTimeToExecute{get{……}}

          public abstract bool Enable { get; }
          public abstract string Name { get; }

          protected MissionBase(IEngine engine)
          {
          ExecuteTimePoints = null;//默認(rèn)采用間隔的方式
          IntervalSeconds = 60 * 60;//默認(rèn)的間隔為1個(gè)小時(shí)

          Engine = engine;
          }

          /// 任務(wù)的執(zhí)行方法
          public void Done()
          {
          if (Interlocked.CompareExchange(ref _isExecuting, 1, 0) == 1) return;

          try
          {
          ……
          }
          finally
          {
          Interlocked.CompareExchange(ref _isExecuting, 0, 1);
          }
          }

          ///實(shí)際方法的執(zhí)行
          protected abstract void DoneReal();
          }

          但是,實(shí)際上這個(gè)任務(wù)方法,并不好用,要寫的代碼不少,而且可靠性還沒(méi)有保障。當(dāng)然,我可以繼續(xù)完善這個(gè)類,但是我決定搜索一下是否還有其他的方法。直到有一天,我再次閱讀《CLR Via C#》,看到線程這一章,講到了System.Threading.Timer以及ThreadPool類時(shí),我就知道了,使用Timer類完全可以解決我的這個(gè)用盡量少的線程完成定時(shí)任務(wù)的問(wèn)題。

          因?yàn)閺脑砩蟻?lái)說(shuō),Timer類無(wú)論你聲明了多少個(gè),其實(shí)就只有一個(gè)線程在執(zhí)行。當(dāng)你到了執(zhí)行時(shí)間時(shí),這個(gè)管理線程會(huì)用ThreadPool來(lái)執(zhí)行Timer中的函數(shù),因?yàn)槭褂玫腡hreadPool,執(zhí)行完成之后,線程就馬上回收了,這個(gè)其實(shí)就完全實(shí)現(xiàn)了我所需要的功能。

          等你無(wú)法重構(gòu)的時(shí)候再考慮重寫

          我?guī)н^(guò)很多優(yōu)秀的程序員,也與很多優(yōu)秀的程序員共事過(guò)。有一大部分的程序員在看到一套系統(tǒng)不是那么滿意,或者存在某些明顯的問(wèn)題,就總是忍不住要把整套系統(tǒng)按自己覺(jué)得可以優(yōu)化的方向來(lái)重寫,結(jié)果,重寫結(jié)構(gòu)往往并不令人滿意。系統(tǒng)中確實(shí)存在很多不合理的地方,但是有不少的這種代碼,恰恰是為了解決一些特定場(chǎng)景下的問(wèn)題的。也就是說(shuō),所有的規(guī)范以及編程的原則,其實(shí)也是有條件限制的,他可能在大部分的時(shí)候是正確的,能夠指導(dǎo)你完成你的任務(wù),但是,并不是在所有地方都是適用的。比如數(shù)據(jù)庫(kù)范式,但實(shí)際中我們的設(shè)計(jì)往往會(huì)考慮冗余,這是違背范式的,但是為什么還有那么多人趨之若鶩呢?因?yàn)槲覀兛赡苄枰每臻g換時(shí)間。

          如果我們一開始就考慮重寫,那么你可能會(huì)陷入以下的困境:

          • 需要花更大的精力來(lái)完成一些看似簡(jiǎn)單的BUG你要知道,有一部分看似錯(cuò)誤或者非常不優(yōu)美的代碼,其實(shí)恰恰是為了解決一些非常刁鉆的問(wèn)題的。
          • 再也無(wú)法兼容老的系統(tǒng)了你急于把原有系統(tǒng)重寫,卻往往忽略了對(duì)原有系統(tǒng)的兼容,那么你新的系統(tǒng)的推進(jìn)則會(huì)十分緩慢。而老系統(tǒng)的維護(hù),又會(huì)陷入及其尷尬的情況。
          • 過(guò)度設(shè)計(jì),導(dǎo)致重寫計(jì)劃遲遲無(wú)法完成有重寫沖動(dòng)的程序員往往是在架構(gòu)設(shè)計(jì)上有一些讀到的見解,他們善于利用所學(xué)的各種設(shè)計(jì)模式和架構(gòu)技巧來(lái)建立系統(tǒng),但是越是想盡可能的利用設(shè)計(jì)模式,越是陷入過(guò)度設(shè)計(jì)的困局,導(dǎo)致重寫的計(jì)劃遲遲都無(wú)法完成。
          • 無(wú)法有效利用現(xiàn)有系統(tǒng)已經(jīng)完成并測(cè)試的代碼如果你確實(shí)有必要進(jìn)行重寫,我還是建議你把代碼盡可能的重構(gòu)。因?yàn)橹貥?gòu)之后的系統(tǒng),能夠讓你更輕易的重寫,又最大限度了保留以前可用的業(yè)務(wù)代碼 。

          我舉個(gè)例子,說(shuō)明如何通過(guò)重構(gòu)更好的利用現(xiàn)有代碼的。

          我有一個(gè)非常龐大的系統(tǒng),其中有一塊功能是用于數(shù)據(jù)采集、存儲(chǔ)、告警管理以及電話、短信等告警通知。大致的結(jié)構(gòu)如下:

          class MainEngine:IEngine{
          public MainEngine(ConfigSettings config){

          }

          public void Start();
          public void Stop();
          }

          需要增加新的業(yè)務(wù)功能時(shí),程序員寫的代碼往往是這樣的:首先時(shí)修改配置類

          class ConfigSettings{
          public bool NewFuncEnable{get;private set;}
          public ConfigSettings(){
          NewFuncEnable=xx;//從配置文件讀取
          }
          }

          接著修改主程序:

          class MainEngine:IEngine{
          private NewFuncClass newCls=new NewFuncClass();
          public MainEngine(ConfigSettings config){
          }

          public void Start(){
          if(config.NewFuncEnable)
          newCls.Start();
          }
          public void Stop(){
          if(config.NewFuncEnable)
          newCls.Stop();
          }
          }

          在修改的過(guò)程中,往往是根據(jù)配置文件來(lái)判斷新功能是否啟用。上面代碼會(huì)造成什么問(wèn)題呢:

          • 主程序代碼和擴(kuò)展功能耦合性太強(qiáng),每增加一個(gè)功能都要修改主程序代碼,這里非常非常容易出錯(cuò)。尤其是新的人進(jìn)度開發(fā)組,很容易就忘主程序中增加了一些致命性的代碼。比如上述的擴(kuò)展功能,可能是在特定的項(xiàng)目中才會(huì)有這個(gè)擴(kuò)展功能,但是,寫代碼的人忘記增加是否啟用的配置 選項(xiàng)了,導(dǎo)致所有的項(xiàng)目都應(yīng)用了這個(gè)功能,而這個(gè)功能需要特定的表,這樣就悲劇了。即使是你增加了配置,也是非常的不美觀,因?yàn)樵谕ㄓ玫陌姹局惺褂昧诉@個(gè)配置,往往會(huì)讓定制項(xiàng)目以外的人員感到困惑 。
          • 增加擴(kuò)展功能的人還需對(duì)整個(gè)MainEngine代碼有一定的熟悉,否則,他根本就不知道在Start方法和Stop方法進(jìn)行newClas的對(duì)應(yīng)方法的調(diào)用
          • 如果你打算對(duì)這段代碼進(jìn)行重寫,那么,你會(huì)感到非常的困難,因?yàn)槟惴植磺宄ewCls這個(gè)新實(shí)例的作用,要么你花大精力去把所有代碼理清楚,要么直接就把這段新增的業(yè)務(wù)代碼去掉了。

          那么我們?nèi)绾螌?duì)這段代碼進(jìn)行重構(gòu)呢。首先,我們把新功能注冊(cè)的代碼抽取出來(lái),通過(guò)反射來(lái)實(shí)現(xiàn)新的功能的注冊(cè)。

              private void RegisterTaskHandlerBundles()
          {
          var bundles = xxx.BLL.Caches.ServiceBundleCache.Instance.GetBundles("TaskHandlerBundle");
          if (bundles != null && bundles.Count > 0)
          {
          var asmCache = new Dictionary();
          foreach (var bundle in bundles)
          {
          try
          {
          if (!asmCache.ContainsKey(bundle.Category)) asmCache.Add(bundle.Category, Assembly.Load(bundle.AssemblyName));
          var handler = (ITaskHandler)asmCache[bundle.Category].CreateInstance(bundle.ClassName, false, BindingFlags.Default, null,
          new object[] { this, bundle }, null, null);
          _taskHandlerBundles.Add(bundle, handler);
          }
          catch (Exception e)
          {
          NLogHelper.Instance.Error("加載bundle[Name:{0},Assembly:{1}:Class:{2}]異常:{3}", bundle.Name, bundle.AssemblyName, bundle.ClassName, e.Message);
          }
          }
          }
          }

          修改MainEngine代碼

          class MainEngine:IEngine{
          private NewFuncClass newCls=new NewFuncClass();
          public MainEngine(ConfigSettings config){
          RegisterTaskHandlerBundles();
          }

          public void Start(){
          _taskHandlerBundles.Start();
          }
          public void Stop(){
          _taskHandlerBundles.Stop();
          }
          }

          OK,現(xiàn)在我們?cè)賮?lái)看看怎么實(shí)現(xiàn)原來(lái)的新增功能:你只需按規(guī)范新建一個(gè)類,繼承ITaskHandler接口,并實(shí)現(xiàn)接口的方法。最后在XTGL_ServiceBundle表中新增一條記錄即可。我們?cè)賮?lái)看看這么做有什么好處:

          • 新增的類只需按規(guī)范寫即可,完全對(duì)MainEngine代碼沒(méi)有任何影響。你甚至可以把這個(gè)MainEngine代碼寫在一個(gè)新建的Dll中。
          • 新增功能的這個(gè)業(yè)務(wù)類跟原來(lái)的代碼解耦,非常方便進(jìn)行新功能的業(yè)務(wù)測(cè)試,而無(wú)需考慮原有框架的影響
          • 新增功能的業(yè)務(wù)類與架構(gòu)完全分離,我們?cè)谥貙懘a中只要保證接口的穩(wěn)定性,無(wú)論我們?cè)趺窗严到y(tǒng)架構(gòu)重寫,我們可以馬上就重用上原有的業(yè)務(wù)功能代碼。

          重構(gòu)的目標(biāo)之一,就是把框架和業(yè)務(wù)完全分離。

          有志于深入了解的同學(xué),可以了解下反射、Ioc和插件話編程等。

          學(xué)會(huì)單元測(cè)試,培養(yǎng)你的重構(gòu)意識(shí)

          可能上面說(shuō)了這么多,還是有很多人并不理解重構(gòu)。沒(méi)關(guān)系,在這里我教你們一個(gè)快速入門的辦法,就是單元測(cè)試 。什么是單元測(cè)試,請(qǐng)自行g(shù)oogle。單元測(cè)試有什么要求?就是要求你要把每個(gè)方法都弄成盡量可以測(cè)試的。盡量讓你的方法變成是可測(cè)試的,就是培養(yǎng)你重構(gòu)意識(shí)的利器 。在你要求把方法變成可測(cè)試的過(guò)程,你就會(huì)發(fā)現(xiàn)你必須得不斷的修改你的方法,讓它的職責(zé)盡量單一,讓它盡量的與上下文無(wú)關(guān),讓它盡可能通過(guò)方法參數(shù)的輸入輸出就能完成相關(guān)的功能,讓依賴的類都盡量改為接口而不是實(shí)例。最終,你就會(huì)發(fā)覺(jué),這就是重構(gòu)!而且是在不知不覺(jué)中,你重構(gòu)的功力就會(huì)大大提升,你編程的水平也會(huì)大大提升!

          看到這里,有經(jīng)驗(yàn)的程序員就會(huì)問(wèn),你這是在鼓勵(lì)我使用TDD嗎?不,不是的。TDD(Test-Driven Development)鼓勵(lì)的是測(cè)試驅(qū)動(dòng)開發(fā),未開發(fā)之前先編寫單元測(cè)試用例代碼,測(cè)試代碼確定需要編寫什么產(chǎn)品代碼。這是一種比較先進(jìn)的開發(fā)方法,但是在編程的實(shí)踐過(guò)程中,我認(rèn)為它過(guò)于繁瑣,很多中小企業(yè)很難實(shí)施,更別提我們個(gè)人開發(fā)者。我這里提倡你用單元測(cè)試培養(yǎng)你的重構(gòu)意識(shí),可以說(shuō)是一種后驅(qū)動(dòng),用于提高你的重構(gòu)能力和重構(gòu)愿望,你完全可以把我的這個(gè)方法稱為“TDR(Test-Driven Refactoring)——測(cè)試驅(qū)動(dòng)重構(gòu) ”。當(dāng)然,在開發(fā)之前如果你有意識(shí)的讓方法可測(cè)試,那么你寫出來(lái)的函數(shù)將會(huì)是比較高質(zhì)量的代碼。當(dāng)你的函數(shù)都是一個(gè)個(gè)可重用性高的函數(shù)之時(shí),你將會(huì)發(fā)現(xiàn),寫代碼其實(shí)就像堆積木一樣,可以把一個(gè)大型的需求分解成無(wú)數(shù)細(xì)小的功能,很快的把需求實(shí)現(xiàn)。

          以下是一個(gè)超大方法中的一段代碼,如果你懂得怎樣讓這段代碼編程一個(gè)可測(cè)試的方法,那么,恭喜你,你入門了。

          所謂重構(gòu)

          如果你有耐心看到這里,你應(yīng)該知道,我并非一個(gè)標(biāo)題黨,而這篇文章也許稱為“如何在編程中應(yīng)用重構(gòu)的思想 ”更為貼切,但是我不想用這么嚴(yán)肅的標(biāo)題。

          很多編程初學(xué)者,或者有多年編程經(jīng)驗(yàn)的人都覺(jué)得閱讀別人的代碼非常困難,重構(gòu)更是無(wú)從談起,他們要么對(duì)這些代碼望洋興嘆,要么就是推翻從來(lái)。但是,如果我們有重構(gòu)的意識(shí),以及在編程的過(guò)程中熟悉一些代碼調(diào)整和優(yōu)化的小技巧,你自然而然就會(huì)培養(yǎng)出重構(gòu)的能力。

          重構(gòu),其實(shí)很簡(jiǎn)單:

          • 把基礎(chǔ)打牢固
          • 多看點(diǎn)優(yōu)秀的代碼
          • 避免復(fù)制粘貼,如果看見重復(fù)代碼時(shí)應(yīng)該有意識(shí)要消滅它
          • 減少對(duì)代碼生成器的依賴
          • 在處理現(xiàn)有代碼時(shí)盡量用重構(gòu)代替重寫,在重寫之前一定要先重構(gòu)
          • 盡量讓所有的方法都是可測(cè)試的

          如果你堅(jiān)持這么去做了,一段時(shí)間之后感覺(jué)自然就出來(lái)了。

          重構(gòu)的目的,是讓你的代碼更為精簡(jiǎn)、穩(wěn)定、能夠重用,是最大程度的讓功能和業(yè)務(wù)分離。在重構(gòu)的過(guò)程中,你的閱讀代碼的能力、寫出優(yōu)秀代碼的能力以及系統(tǒng)架構(gòu)能力都會(huì)穩(wěn)步提升 。你成為一個(gè)優(yōu)秀的程序員將指日可待

          END



          若覺(jué)得文章對(duì)你有幫助,隨手轉(zhuǎn)發(fā)分享,也是我們繼續(xù)更新的動(dòng)力。


          長(zhǎng)按二維碼,掃掃關(guān)注哦

          ?「C語(yǔ)言中文網(wǎng)」官方公眾號(hào),關(guān)注手機(jī)閱讀教程??



          點(diǎn)擊“閱讀原文”,領(lǐng)取 2020 年最新免費(fèi)技術(shù)資料大全

          ↓↓↓?
          瀏覽 42
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲色图网站 | 韩国精品在线观看 | 亚洲男人的天堂网 | 欧美黄色大片免费在线观看 | 欧美日韩123区不卡 |