您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關(guān)如何消除Java代碼中一大串參數(shù)列表,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
因為不同方法間需共享信息。
但方法間共享信息的方式不止一種,除了參數(shù)列表,還有全局變量。但全局變量總能帶來意外驚喜,所以,取消全局變量也是各大語言的趨勢。
但方法之間還是要傳遞信息的,不能用全局變量,于是參數(shù)就成了唯一選擇,于是,只要你想到有什么信息要傳給一個方法,就會直接它加到參數(shù)列表中,參數(shù)列表也越來越長。
參數(shù)列表過長,你一個 crud 程序員就很難完全掌控這些邏輯了呀!
所以癥結(jié)是數(shù)量多,解決關(guān)鍵也就在于降低參數(shù)的數(shù)量。
一個簡單的創(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ù)列表包含了一篇博客所要擁有的各種信息,比如:博客標題、博客簡介、封面 URL、博客類型、博客歸屬的專欄、主角姓名、博客標簽、博客是否完結(jié)…
如果只是想理解邏輯,或許你還會覺得參數(shù)列表挺合理,畢竟它把創(chuàng)建一篇博客所需的各種信息都傳給了方法,這也是大部分人面對一段代碼時理解問題的最初角度。
雖然這樣寫代碼容易讓人理解,但這不足以讓你發(fā)現(xiàn)問題。
現(xiàn)在產(chǎn)品要求在博客里增加一項信息,標識這部博客是否是簽約博客,也就是這部博客是否可收費,咋辦?
很簡單啊!我直接新增一個參數(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è)計角度,這里引入的是一個新模型。
一個模型的封裝應該以【行為】為基礎(chǔ)。
之前沒有這個模型,所以想不到它應該有什么行為,現(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); }
“如何擴展需求”?如果需求擴展,需要增加創(chuàng)建博客所需的內(nèi)容,那這個參數(shù)列表就是不變的,相對來說,它就是穩(wěn)定的。
那這個類就會不斷膨脹,變成一個大類,那該怎么辦呢?如何解決大類?
不是所有情況下,參數(shù)都屬于一個類:
public void getChapters(final long acticleId, final HttpClient httpClient, final ChapterProcessor processor) { HttpUriRequest request = createChapterRequest(acticleId); HttpResponse response = httpClient.execute(request); List<Chapter> chapters = toChapters(response); processor.process(chapters); }
根據(jù)博客 ID 獲取其對應章節(jié)信息。
純以參數(shù)個數(shù)論,參數(shù)數(shù)量不多。
如果你只是看這個方法,可能很難發(fā)現(xiàn)直接問題。絕對數(shù)量不是關(guān)鍵點,參數(shù)列表也應該是越少越好。
在這幾個參數(shù)里面,每次傳進來的 acticleId 都不一樣,隨請求不同而改變。但 httpClient 和 processor 兩個參數(shù)一樣,因為都有相同邏輯,沒什么變化。
即acticleId 的變化頻率同 httpClient 和 processor 這兩個參數(shù)變化頻率不同。
不同的數(shù)據(jù)變動方向也是不同關(guān)注點。這里表現(xiàn)出來的就是典型的動數(shù)據(jù)(acticleId)和靜數(shù)據(jù)(httpClient 和 processor),它們是不同關(guān)注點,應該分離。
具體到這個場景下,靜態(tài)不變的數(shù)據(jù)完全可以成為這個方法所在類的一個字段,而只將每次變動的東西作為參數(shù)傳遞就可以了。按照這個思路,代碼可以改成這個樣子:
public void getChapters(final long acticleId) { HttpUriRequest request = createChapterRequest(acticleId); HttpResponse response = this.httpClient.execute(request); List<Chapter> chapters = toChapters(response); this.processor.process(chapters); }
這個壞味道其實是一個軟件設(shè)計問題,代碼缺乏應有的結(jié)構(gòu),所以,原本應該屬于靜態(tài)結(jié)構(gòu)的部分卻以動態(tài)參數(shù)的方式傳來傳去,無形之中拉長了參數(shù)列表。
長參數(shù)列表固然可以用一個類進行封裝,但能夠封裝出這個類的前提條件是:這些參數(shù)屬于一個類,有相同變化原因。
如果方法的參數(shù)有不同的變化頻率,就要視情況而定了。對于靜態(tài)的部分,我們前面已經(jīng)看到了,它可以成為軟件結(jié)構(gòu)的一篇分,而如果有多個變化頻率,我們還可以封裝出多個參數(shù)類。
public void editChapter(final long chapterId, final String title, final String content, final boolean apporved) { ... }
待修改章節(jié)的ID、標題和內(nèi)容,最后一個參數(shù)表示這次修改是否直接審核通過。
前面幾個參數(shù)是修改一個章節(jié)的必要信息,重點在最后這個參數(shù)。
從業(yè)務上說,如果是作者進行編輯,之后要經(jīng)過審核,而如果編輯來編輯的,那審核就直接通過,因為編輯本身扮演了審核人的角色。所以,你發(fā)現(xiàn)了,這個參數(shù)實際上是一個標記,標志著接下來的處理流程會有不同。
使用標記參數(shù),是程序員初學編程時常用的一種手法。正是這種手法實在太好用,導致代碼里flag肆意飄蕩。不僅變量里有標記,參數(shù)里也有。很多長參數(shù)列表其中就包含了各種標記參數(shù)。
在實際的代碼中,必須小心翼翼地判斷各個標記當前的值,才能做好處理。
解決標記參數(shù),一種簡單的方式就是,將標記參數(shù)代表的不同路徑拆分出來。
這里的一個方法可以拆分成兩個方法,一個方法負責“普通的編輯”,另一個負責“可以直接審核通過的編輯”。
// 普通的編輯,需要審核 public void editChapter(final long chapterId, final String title, final String content) { ... }
// 直接審核通過的編輯 public void editChapterWithApproval(final long chapterId, final String title, final String content) { ... }
標記參數(shù)在代碼中存在的形式很多,有的是布爾值、枚舉值、字符串或整數(shù)。都可以通過拆分方法的方式將它們拆開。在重構(gòu)中,這種手法叫做移除標記參數(shù)(Remove Flag Argument)。
只有短小的代碼,我們才能有更好地把握,而要寫出短小的代碼,需要我們能夠“分離關(guān)注點”。
應對長參數(shù)列表主要的方式就是減少參數(shù)的數(shù)量,最直接的就是將參數(shù)列表封裝成一個類。但并不是說所有的情況都能封裝成類來解決,我們還要分析是否所有的參數(shù)都有相同的變動頻率。
變化頻率相同,則封裝成一個類。
變化頻率不同的話:
靜態(tài)不變的,可以成為軟件結(jié)構(gòu)的一篇分
多個變化頻率的,可以封裝成幾個類
此外,參數(shù)列表中經(jīng)常會出現(xiàn)標記參數(shù),這是參數(shù)列表變長的另一個重要原因。對于這種標記參數(shù),一種解決方案就是根據(jù)這些標記參數(shù),將方法拆分成多個方法。
減少參數(shù)列表,越少越好。
看完上述內(nèi)容,你們對如何消除Java代碼中一大串參數(shù)列表有進一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。