如何消除代碼山中的一大坨參數(shù)列表?

      網(wǎng)友投稿 663 2022-05-30

      有經(jīng)驗的程序員應(yīng)該都見過,一個方法坐擁幾十上百個參數(shù)。

      1 方法為何要有參數(shù)?

      因為不同方法之間需要共享信息。

      但方法間共享信息的方式除了參數(shù)列表,還有全局變量。但全局變量總能帶來意外之喜,所以,取消全局變量也是各大語言趨勢。于是參數(shù)列表就成了唯一選擇,于是,只要你想到有什么信息要傳給一個方法,就會直接將其加入?yún)?shù)列表,導(dǎo)致參數(shù)列表越來越長!

      2 長參數(shù)列表怎么了?

      參數(shù)列表一旦過長,你一個 crud boy就很難完全掌控這些邏輯了呀!所以癥結(jié)是數(shù)量多,解決關(guān)鍵也就是降低參數(shù)數(shù)量。

      3 解決方案

      3.1 聚沙成塔

      一個簡單的創(chuàng)建博客的方法:

      public void createActicle(final String title, final String introduction, final URL coverUrl, final ActicleType type, final ActicleColumn column, final String protagonists, final String tags, final boolean completed) { ... Acticle acticle = Acticle.builder .title(title) .introduction(introduction) .coverUrl(coverUrl) .type(type) .column(column) .protagonists(protagonists) .tags(tags) .completed(completed) .build(); this.repository.save(acticle); }

      參數(shù)列表包含了一篇博客所要擁有的各種信息,比如:博客標(biāo)題、簡介、封面 URL、類型、歸屬專欄、主角姓名、標(biāo)簽、是否完結(jié)…

      若只是想理解邏輯,可能你還會覺得這參數(shù)列表挺好啊,把創(chuàng)建一篇博客所需的信息都傳給了方法,這也是大部分人面對一段代碼時理解問題的最初角度。雖然這樣寫代碼容易讓人理解,但不足以讓你發(fā)現(xiàn)問題。

      現(xiàn)在產(chǎn)品要求在博客里增加一項信息,標(biāo)識這部博客是否收費,咋辦?很簡單啊!我直接新增一個參數(shù)。很多屎山就這么來的,積少成多,量變引起質(zhì)變!

      這里所有參數(shù)都是創(chuàng)建博客所必需,所以,可以做的就是將這些參數(shù)封裝成一個類,一個創(chuàng)建博客的參數(shù)類:

      public class NewActicleParamters { private String title; private String introduction; private URL coverUrl; private ActicleType type; private ActicleColumn column; private String protagonists; private String tags; private boolean completed; ... }

      這樣參數(shù)列表就只剩下一個參數(shù)了:

      public void createActicle(final NewActicleParamters parameters) { ... }

      所以, 將參數(shù)列表封裝成對象吧 !

      只是把一個參數(shù)列表封裝成一個類,然后,用到這些參數(shù)的時候,還需要把它們一個個取出來,這會不會是多此一舉呢?就像這樣:

      public void createActicle(final NewActicleParamters parameters) { ... Acticle acticle = Acticle.builder .title(parameters.getTitle()) .introduction(parameters.getIntroduction()) .coverUrl(parameters.getCoverUrl()) .type(parameters.getType()) .channel(parameters.getChannel()) .protagonists(parameters.getProtagonists()) .tags(parameters.getTags()) .completed(parameters.isCompleted()) .build(); this.repository.save(acticle); }

      若你這樣想,說明還沒有形成對軟件設(shè)計的理解。我們并非只是簡單地把參數(shù)封裝成類,站在設(shè)計角度,這里引入的是一個新模型。

      一個模型的封裝應(yīng)該以【行為】為基礎(chǔ)。

      之前沒有這個模型,所以想不到它應(yīng)該有什么行為,現(xiàn)在模型產(chǎn)生了,它就該有自己配套的行為。

      該模型的行為就是構(gòu)建一個博客對象,則代碼就能進一步重構(gòu):

      public class NewActicleParamters { private String title; private String introduction; private URL coverUrl; private ActicleType type; private ActicleColumn column; private String protagonists; private String tags; private boolean completed; public Acticle newActicle() { return Acticle.builder .title(title) .introduction(introduction) .coverUrl(coverUrl) .type(type) .column(column) .protagonists(protagonists) .tags(tags) .completed(completed) .build(); } }

      創(chuàng)建博客的方法就得到極大簡化:

      public void createActicle(final NewActicleParamters parameters) { ... Acticle acticle = parameters.newActicle(); this.repository.save(acticle); }

      如此,一旦后續(xù)需求又?jǐn)U展了,需要增加創(chuàng)建博客所需的內(nèi)容,則該參數(shù)列表是不變的,也就是說它是穩(wěn)定的!

      如何消除代碼屎山中的一大坨參數(shù)列表?

      3.2 動靜分離

      若這個類不斷膨脹,變成一個大類,該咋辦?畢竟并非所有場景下,參數(shù)都屬于一個類:

      // 根據(jù)博客 ID 獲取對應(yīng)章節(jié)信息 public void getSections(final long acticleId, final HttpClient httpClient, final SectionProcessor processor) { HttpUriRequest request = createChapterRequest(acticleId); HttpResponse response = httpClient.execute(request); List

      sections = toSections(response); processor.process(sections); }

      單論參數(shù)的個數(shù),數(shù)量并不多。若你只看這個方法,很難發(fā)現(xiàn)直接問題。絕對數(shù)量不是core,參數(shù)列表也應(yīng)該是越少越好。

      但注意,每次傳進來的參數(shù):

      acticleId 都隨請求不同而改變

      但 httpClient、processor 兩個參數(shù)一樣,因為都有相同邏輯,沒啥變化。

      即acticleId 的變化頻率同 httpClient 和 processor 這兩個參數(shù)變化頻率不同。

      **不同的數(shù)據(jù)變動方向也是不同關(guān)注點。**這里表現(xiàn)出來的就是典型的動數(shù)據(jù)(acticleId)和靜數(shù)據(jù)(httpClient、processor),它們是不同關(guān)注點,應(yīng)該分離。

      針對該案例:

      靜態(tài)不變的數(shù)據(jù)完全可以成為這個方法所在類的一個字段

      只將每次變動的東西作為參數(shù)傳遞即可

      因此,代碼可重構(gòu)如下:

      public void getSections(final long acticleId) { HttpUriRequest request = createChapterRequest(acticleId); HttpResponse response = this.httpClient.execute(request); List

      sections = toSections(response); this.processor.process(sections); }

      這個壞味道是個軟件設(shè)計問題,代碼缺乏應(yīng)有的結(jié)構(gòu),所以,原本應(yīng)該屬于靜態(tài)結(jié)構(gòu)的部分卻以動態(tài)參數(shù)的方式傳來傳去,無形中導(dǎo)致參數(shù)列表變長。

      長參數(shù)列表固然可以用一個類進行封裝,但能夠封裝成這個類的前提是:這些參數(shù)屬于一個類,有相同的變化原因!

      若方法的參數(shù)有不同變化頻率,就要看情況了。對靜態(tài)部分,本小節(jié)案例已經(jīng)看出,它可以成為軟件結(jié)構(gòu)的一部分,而若有多個變化頻率,則還可以封裝出多個參數(shù)類。

      3.3 再見了,標(biāo)記!

      public void editChapter(final long chapterId, final String title, final String content, final boolean apporved) { ... }

      待修改章節(jié)的ID、標(biāo)題和內(nèi)容,最后一個參數(shù)表示這次修改是否直接審核通過。

      使用標(biāo)記參數(shù),是程序員初學(xué)編程時常用的一種手法。正是這種手法實在太好用,導(dǎo)致代碼里flag肆意飄蕩。不僅變量里有標(biāo)記,參數(shù)里也有。很多長參數(shù)列表其中就包含了各種標(biāo)記參數(shù)。

      在實際的代碼中,必須小心翼翼地判斷各個標(biāo)記當(dāng)前的值,才能做好處理。

      解決標(biāo)記參數(shù),一種簡單的方式就是,將標(biāo)記參數(shù)代表的不同路徑拆分出來。

      這里的一個方法可以拆分成兩個方法,一個方法負(fù)責(zé)“普通的編輯”,另一個負(fù)責(zé)“可以直接審核通過的編輯”。

      // 普通的編輯,需要審核 public void editChapter(final long chapterId, final String title, final String content) { ... }

      // 直接審核通過的編輯 public void editChapterWithApproval(final long chapterId, final String title, final String content) { ... }

      標(biāo)記參數(shù)在代碼中存在的形式很多,有的是布爾值、枚舉值、字符串或整數(shù)。都可以通過拆分方法的方式將它們拆開。在重構(gòu)中,這種手法叫做移除標(biāo)記參數(shù)(Remove Flag Argument)。

      只有短小的代碼,我們才能有更好地把握,而要寫出短小的代碼,需要我們能夠“分離關(guān)注點”。

      總結(jié)

      應(yīng)對長參數(shù)列表主要的方式就是減少參數(shù)的數(shù)量,最直接的就是將參數(shù)列表封裝成一個類。但并不是說所有的情況都能封裝成類來解決,我們還要分析是否所有的參數(shù)都有相同的變動頻率。

      變化頻率相同,則封裝成一個類。

      變化頻率不同的話:

      靜態(tài)不變的,可以成為軟件結(jié)構(gòu)的一篇分

      多個變化頻率的,可以封裝成幾個類

      此外,參數(shù)列表中經(jīng)常會出現(xiàn)標(biāo)記參數(shù),這是參數(shù)列表變長的另一個重要原因。對于這種標(biāo)記參數(shù),一種解決方案就是根據(jù)這些標(biāo)記參數(shù),將方法拆分成多個方法。

      開發(fā)者

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:手撕環(huán)形隊列系列二:無鎖實現(xiàn)高并發(fā)
      下一篇:微軟擁抱開源,Win10為啥要引入真Linux4.X內(nèi)核?
      相關(guān)文章
      亚洲精品tv久久久久| 亚洲精品无码久久久久秋霞 | 亚洲精品无码成人片久久不卡| 久久精品国产亚洲77777| 亚洲AV无码AV男人的天堂| 亚洲精品国产精品乱码不卡√| 亚洲日本乱码在线观看| 337p日本欧洲亚洲大胆裸体艺术| 亚洲区不卡顿区在线观看| 亚洲人成网站18禁止一区| 亚洲伊人久久综合影院| 亚洲综合最新无码专区| 亚洲精品乱码久久久久久久久久久久| 最新国产AV无码专区亚洲| 亚洲日产无码中文字幕| 亚洲av无码一区二区三区网站| 亚洲国产精彩中文乱码AV| 亚洲AV人无码综合在线观看| 亚洲午夜久久久精品影院| 亚洲美女视频一区| 亚洲人配人种jizz| 亚洲精品无码不卡在线播放| 狠狠入ady亚洲精品| 亚洲精品无码专区2| 国产gv天堂亚洲国产gv刚刚碰| 亚洲第一极品精品无码久久| 亚洲伦另类中文字幕| 亚洲日本在线免费观看| 亚洲一区欧洲一区| 亚洲国产精品无码久久98| 国产亚洲午夜精品| 亚洲日产无码中文字幕| 亚洲国产天堂久久综合网站| 亚洲综合小说久久另类区| 色婷五月综激情亚洲综合| 亚洲AV无码专区在线观看成人| 亚洲国产精品一区二区三区久久| 中文字幕第13亚洲另类| 亚洲成人免费在线| 亚洲一区电影在线观看| 亚洲av永久无码精品秋霞电影秋 |