溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何理解Java重復(fù)代碼

發(fā)布時(shí)間:2021-10-08 10:02:22 來源:億速云 閱讀:141 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“如何理解Java重復(fù)代碼”,在日常操作中,相信很多人在如何理解Java重復(fù)代碼問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何理解Java重復(fù)代碼”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

目錄
  • 方法為何要有參數(shù)?

  • 長參數(shù)列表的問題

  • 解決方案

    • 聚沙成塔

    • 動(dòng)靜分離

    • 告別標(biāo)記

  • 總結(jié)

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

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

    因?yàn)椴煌椒ㄩg需共享信息。

    但方法間共享信息的方式不止一種,除了參數(shù)列表,還有全局變量。但全局變量總能帶來意外驚喜,所以,取消全局變量也是各大語言的趨勢。

    但方法之間還是要傳遞信息的,不能用全局變量,于是參數(shù)就成了唯一選擇,于是,只要你想到有什么信息要傳給一個(gè)方法,就會(huì)直接它加到參數(shù)列表中,參數(shù)列表也越來越長。

    長參數(shù)列表的問題

    參數(shù)列表過長,你一個(gè) crud 程序員就很難完全掌控這些邏輯了呀!

    所以癥結(jié)是數(shù)量多,解決關(guān)鍵也就在于降低參數(shù)的數(shù)量。

    解決方案

    聚沙成塔

    一個(gè)簡單的創(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é)…

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

    現(xiàn)在產(chǎn)品要求在博客里增加一項(xiàng)信息,標(biāo)識這部博客是否是簽約博客,也就是這部博客是否可收費(fèi),咋辦?

    很簡單?。∥抑苯有略鲆粋€(gè)參數(shù)。很多屎山就這么來的,積少成多,量變引起質(zhì)變!

    這里所有參數(shù)都是創(chuàng)建博客所必需的。所以,可以做的就是將這些參數(shù)封裝成一個(gè)類,一個(gè)創(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ù)列表就只剩下一個(gè)參數(shù)了:

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

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

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

    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è)計(jì)的理解。我們并非簡單地把參數(shù)封裝成類,站在設(shè)計(jì)角度,這里引入的是一個(gè)新模型。
    一個(gè)模型的封裝應(yīng)該以【行為】為基礎(chǔ)。
    之前沒有這個(gè)模型,所以想不到它應(yīng)該有什么行為,現(xiàn)在模型產(chǎn)生了,它就該有自己配套的行為。

    那這個(gè)模型的行為是什么?構(gòu)建一個(gè)博客對象,這很清晰,則代碼就能進(jìn)一步重構(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);
    }

    “如何擴(kuò)展需求”?如果需求擴(kuò)展,需要增加創(chuàng)建博客所需的內(nèi)容,那這個(gè)參數(shù)列表就是不變的,相對來說,它就是穩(wěn)定的。

    那這個(gè)類就會(huì)不斷膨脹,變成一個(gè)大類,那該怎么辦呢?如何解決大類?

    動(dòng)靜分離

    不是所有情況下,參數(shù)都屬于一個(gè)類:

    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 獲取其對應(yīng)章節(jié)信息。
    純以參數(shù)個(gè)數(shù)論,參數(shù)數(shù)量不多。

    如果你只是看這個(gè)方法,可能很難發(fā)現(xiàn)直接問題。絕對數(shù)量不是關(guān)鍵點(diǎn),參數(shù)列表也應(yīng)該是越少越好。

    在這幾個(gè)參數(shù)里面,每次傳進(jìn)來的 acticleId 都不一樣,隨請求不同而改變。但 httpClient 和 processor 兩個(gè)參數(shù)一樣,因?yàn)槎加邢嗤壿?,沒什么變化。
    即acticleId 的變化頻率同 httpClient 和 processor 這兩個(gè)參數(shù)變化頻率不同。

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

    具體到這個(gè)場景下,靜態(tài)不變的數(shù)據(jù)完全可以成為這個(gè)方法所在類的一個(gè)字段,而只將每次變動(dòng)的東西作為參數(shù)傳遞就可以了。按照這個(gè)思路,代碼可以改成這個(gè)樣子:

    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);
    }

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

    長參數(shù)列表固然可以用一個(gè)類進(jìn)行封裝,但能夠封裝出這個(gè)類的前提條件是:這些參數(shù)屬于一個(gè)類,有相同變化原因。

    如果方法的參數(shù)有不同的變化頻率,就要視情況而定了。對于靜態(tài)的部分,我們前面已經(jīng)看到了,它可以成為軟件結(jié)構(gòu)的一篇分,而如果有多個(gè)變化頻率,我們還可以封裝出多個(gè)參數(shù)類。

    告別標(biāo)記

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

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

    前面幾個(gè)參數(shù)是修改一個(gè)章節(jié)的必要信息,重點(diǎn)在最后這個(gè)參數(shù)。
    從業(yè)務(wù)上說,如果是作者進(jìn)行編輯,之后要經(jīng)過審核,而如果編輯來編輯的,那審核就直接通過,因?yàn)榫庉嫳旧戆缪萘藢徍巳说慕巧?。所以,你發(fā)現(xiàn)了,這個(gè)參數(shù)實(shí)際上是一個(gè)標(biāo)記,標(biāo)志著接下來的處理流程會(huì)有不同。

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

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

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

    這里的一個(gè)方法可以拆分成兩個(gè)方法,一個(gè)方法負(fù)責(zé)“普通的編輯”,另一個(gè)負(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)注點(diǎn)”。

    總結(jié)

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

    變化頻率相同,則封裝成一個(gè)類。
    變化頻率不同的話:

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

    • 多個(gè)變化頻率的,可以封裝成幾個(gè)類

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

    減少參數(shù)列表,越少越好。

    到此,關(guān)于“如何理解Java重復(fù)代碼”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI