怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅-創(chuàng)新互聯(lián)

基本類型偏執(zhí)

基本類型偏執(zhí)(Primitive Obsession)

成都創(chuàng)新互聯(lián)主要從事成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)貴州,十余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18980820575
  • 使用基本類型而不是小對象來實(shí)現(xiàn)簡單任務(wù)(例如貨幣、范圍、電話號碼字符串等)。
  • 使用常量編碼信息(例如一個用于引用管理員權(quán)限的常量 USER_ADMIN_ROLE = 1  )。
  • 使用字符串常量作為字段名在數(shù)組中使用。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

問題原因

類似其他大部分壞味道,基本類型偏執(zhí)誕生于類初建的時候。一開始,可能只是不多的字段,隨著表示的特性越來越多,基本數(shù)據(jù)類型字段也越來越多。

基本類型常常被用于表示模型的類型。你有一組數(shù)字或字符串用來表示某個實(shí)體。

還有一個場景:在模擬場景,大量的字符串常量被用于數(shù)組的索引。

解決方法

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

大多數(shù)編程語言都支持基本數(shù)據(jù)類型和結(jié)構(gòu)類型(類、結(jié)構(gòu)體等)。結(jié)構(gòu)類型允許程序員將基本數(shù)據(jù)類型組織起來,以代表某一事物的模型。

基本數(shù)據(jù)類型可以看成是機(jī)構(gòu)類型的積木塊。當(dāng)基本數(shù)據(jù)類型數(shù)量成規(guī)模后,將它們有組織地結(jié)合起來,可以更方便的管理這些數(shù)據(jù)。

  • 如果你有大量的基本數(shù)據(jù)類型字段,就有可能將其中部分存在邏輯聯(lián)系的字段組織起來,形成一個類。更進(jìn)一步的是,將與這些數(shù)據(jù)有關(guān)聯(lián)的方法也一并移入類中。為了實(shí)現(xiàn)這個目標(biāo),可以嘗試  以類取代類型碼(Replace Type Code with Class)  。
  • 如果基本數(shù)據(jù)類型字段的值是用于方法的參數(shù),可以使用  引入?yún)?shù)對象(Introduce Parameter Object)  或  保持對象完整(Preserve Whole Object)  。
  • 如果想要替換的數(shù)據(jù)值是類型碼,而它并不影響行為,則可以運(yùn)用  以類取代類型碼(Replace Type Code with Class)  將它替換掉。如果你有與類型碼相關(guān)的條件表達(dá)式,可運(yùn)用  以子類取代類型碼(Replace Type Code with Subclass)  或  以狀態(tài)/策略模式取代類型碼(Replace Type Code with State/Strategy)  加以處理。
  • 如果你發(fā)現(xiàn)自己正從數(shù)組中挑選數(shù)據(jù),可運(yùn)用  以對象取代數(shù)組(Replace Array with Object)  。

收益

  • 多虧了使用對象替代基本數(shù)據(jù)類型,使得代碼變得更加靈活。
  • 代碼變得更加易讀和更加有組織。特殊數(shù)據(jù)可以集中進(jìn)行操作,而不像之前那樣分散。不用再猜測這些陌生的常量的意義以及它們?yōu)槭裁丛跀?shù)組中。
  • 更容易發(fā)現(xiàn)重復(fù)代碼。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

重構(gòu)方法說明

以類取代類型碼(Replace Type Code with Class)

問題

類之中有一個數(shù)值類型碼,但它并不影響類的行為。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

解決

以一個新的類替換該數(shù)值類型碼。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

引入?yún)?shù)對象(Introduce Parameter Object)

問題

某些參數(shù)總是很自然地同時出現(xiàn)。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

解決

以一個對象來取代這些參數(shù)。 

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

保持對象完整(Preserve Whole Object)

問題

你從某個對象中取出若干值,將它們作為某一次函數(shù)調(diào)用時的參數(shù)。

int low = daysTempRange.getLow();
int high = daysTempRange.getHigh();
boolean withinPlan = plan.withinRange(low, high);

解決

改為傳遞整個對象。

boolean withinPlan = plan.withinRange(daysTempRange);

以子類取代類型碼(Replace Type Code with Subclass)

問題

你有一個不可變的類型碼,它會影響類的行為。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

解決

以子類取代這個類型碼。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

以狀態(tài)/策略模式取代類型碼(Replace Type Code with State/Strategy)

問題

你有一個類型碼,它會影響類的行為,但你無法通過繼承消除它。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

解決

以狀態(tài)對象取代類型碼。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

以對象取代數(shù)組(Replace Array with Object)

問題

你有一個數(shù)組,其中的元素各自代表不同的東西。

String[] row = new String[3];
row[0] = "Liverpool";
row[1] = "15";

解決

以對象替換數(shù)組。對于數(shù)組中的每個元素,以一個字段來表示。

Performance row = new Performance();
row.setName("Liverpool");
row.setWins("15");

數(shù)據(jù)泥團(tuán)

數(shù)據(jù)泥團(tuán)(Data Clumps)

有時,代碼的不同部分包含相同的變量組(例如用于連接到數(shù)據(jù)庫的參數(shù))。這些綁在一起出現(xiàn)的數(shù)據(jù)應(yīng)該擁有自己的對象。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

問題原因

通常,數(shù)據(jù)泥團(tuán)的出現(xiàn)時因?yàn)樵愀獾木幊探Y(jié)構(gòu)或“復(fù)制-粘貼式編程”。

有一個判斷是否是數(shù)據(jù)泥團(tuán)的好辦法:刪掉眾多數(shù)據(jù)中的一項(xiàng)。這么做,其他數(shù)據(jù)有沒有因而失去意義?如果它們不再有意義,這就是個明確的信號:你應(yīng)該為它們產(chǎn)生一個新的對象。

解決方法

  • 首先找出這些數(shù)據(jù)以字段形式出現(xiàn)的地方,運(yùn)用  提煉類(Extract Class)  將它們提煉到一個獨(dú)立對象中。
  • 如果數(shù)據(jù)泥團(tuán)在函數(shù)的參數(shù)列中出現(xiàn),運(yùn)用  引入?yún)?shù)對象(Introduce Parameter Object)  將它們組織成一個類。
  • 如果數(shù)據(jù)泥團(tuán)的部分?jǐn)?shù)據(jù)出現(xiàn)在其他函數(shù)中,考慮運(yùn)用  保持對象完整(Preserve Whole Object)  將整個數(shù)據(jù)對象傳入到函數(shù)中。
  • 檢視一下使用這些字段的代碼,也許,將它們移入一個數(shù)據(jù)類是個不錯的主意。

收益

  • 提高代碼易讀性和組織性。對于特殊數(shù)據(jù)的操作,可以集中進(jìn)行處理,而不像以前那樣分散。
  • 減少代碼量。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

何時忽略

  • 有時為了對象中的部分?jǐn)?shù)據(jù)而將整個對象作為參數(shù)傳遞給函數(shù),可能會產(chǎn)生讓兩個類之間不收歡迎的依賴關(guān)系,這中情況下可以不傳遞整個對象。

重構(gòu)方法說明

提煉類(Extract Class)

問題

某個類做了不止一件事。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

解決

建立一個新類,將相關(guān)的字段和函數(shù)從舊類搬移到新類。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

引入?yún)?shù)對象(Introduce Parameter Object)

問題

某些參數(shù)總是很自然地同時出現(xiàn)。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

解決

以一個對象來取代這些參數(shù)。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

保持對象完整(Preserve Whole Object)

問題

你從某個對象中取出若干值,將它們作為某一次函數(shù)調(diào)用時的參數(shù)。

int low = daysTempRange.getLow();
int high = daysTempRange.getHigh();
boolean withinPlan = plan.withinRange(low, high);

解決

改為傳遞整個對象。

boolean withinPlan = plan.withinRange(daysTempRange);

過大的類

過大的類(Large Class)

一個類含有過多字段、函數(shù)、代碼行。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

問題原因

類通常一開始很小,但是隨著程序的增長而逐漸膨脹。

類似于過長函數(shù),程序員通常覺得在一個現(xiàn)存類中添加新特性比創(chuàng)建一個新的類要容易。

解決方法

設(shè)計(jì)模式中有一條重要原則:職責(zé)單一原則。一個類應(yīng)該只賦予它一個職責(zé)。如果它所承擔(dān)的職責(zé)太多,就該考慮為它減減負(fù)。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

  • 如果過大類中的部分行為可以提煉到一個獨(dú)立的組件中,可以使用  提煉類(Extract Class)
  • 如果過大類中的部分行為可以用不同方式實(shí)現(xiàn)或使用于特殊場景,可以使用  提煉子類(Extract Subclass) 。
  • 如果有必要為客戶端提供一組操作和行為,可以使用  提煉接口(Extract Interface) 。
  • 如果你的過大類是個 GUI 類,可能需要把數(shù)據(jù)和行為移到一個獨(dú)立的領(lǐng)域?qū)ο笕?。你可能需要兩邊各保留一些重?fù)數(shù)據(jù),并保持兩邊同步。  復(fù)制被監(jiān)視數(shù)據(jù)(Duplicate Observed Data)  可以告訴你怎么做。

收益

  • 重構(gòu)過大的類可以使程序員不必記住一個類中大量的屬性。
  • 在大多數(shù)情況下,分割過大的類可以避免代碼和功能的重復(fù)。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

重構(gòu)方法說明

提煉類(Extract Class)

問題

某個類做了不止一件事。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

解決

建立一個新類,將相關(guān)的字段和函數(shù)從舊類搬移到新類。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

提煉子類(Extract Subclass)

問題

一個類中有些特性僅用于特定場景。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

解決

創(chuàng)建一個子類,并將用于特殊場景的特性置入其中。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

提煉接口(Extract Interface)

問題

多個客戶端使用一個類部分相同的函數(shù)。另一個場景是兩個類中的部分函數(shù)相同。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

解決

移動相同的部分函數(shù)到接口中。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

復(fù)制被監(jiān)視數(shù)據(jù)(Duplicate Observed Data)

問題

如果存儲在類中的數(shù)據(jù)是負(fù)責(zé) GUI 的。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

解決

一個比較好的方法是將負(fù)責(zé) GUI 的數(shù)據(jù)放入一個獨(dú)立的類,以確保 GUI 數(shù)據(jù)與域類之間的連接和同步。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

過長函數(shù)

過長函數(shù)(Long Method)

一個函數(shù)含有太多行代碼。一般來說,任何函數(shù)超過 10 行時,你就可以考慮是不是過長了。 函數(shù)中的代碼行數(shù)原則上不要超過 100 行。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

問題的原因

通常情況下,創(chuàng)建一個新函數(shù)的難度要大于添加功能到一個已存在的函數(shù)。大部分人都覺得:“我就添加這么兩行代碼,為此新建一個函數(shù)實(shí)在是小題大做了。”于是,張三加兩行,李四加兩行,王五加兩行。。。函數(shù)日益龐大,最終爛的像一鍋漿糊,再也沒人能完全看懂了。于是大家就更不敢輕易動這個函數(shù)了,只能惡性循環(huán)的往其中添加代碼。所以,如果你看到一個超過 200 行的函數(shù),通常都是多個程序員東拼西湊出來的。

解決函數(shù)

一個很好的技巧是: 尋找注釋 。添加注釋,一般有這么幾個原因:代碼邏輯較為晦澀或復(fù)雜;這段代碼功能相對獨(dú)立;特殊處理。 如果代碼前方有一行注釋,就是在提醒你:可以將這段代碼替換成一個函數(shù),而且可以在注釋的基礎(chǔ)上給這個函數(shù)命名。如果函數(shù)有一個描述恰當(dāng)?shù)拿?,就不需要去看?nèi)部代碼究竟是如何實(shí)現(xiàn)的。就算只有一行代碼,如果它需要以注釋來說明,那也值得將它提煉到獨(dú)立函數(shù)中。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

 

  • 為了給一個函數(shù)瘦身,可以使用  提煉函數(shù)(Extract Method) 。
  • 如果局部變量和參數(shù)干擾提煉函數(shù),可以使用  以查詢?nèi)〈R時變量(Replace Temp with Query) , 引入?yún)?shù)對象(Introduce Parameter Object)  或  保持對象完整(Preserve Whole Object)  。
  • 如果前面兩條沒有幫助,可以通過  以函數(shù)對象取代函數(shù)(Replace Method with Method Object)  嘗試移動整個函數(shù)到一個獨(dú)立的對象中。
  • 條件表達(dá)式和循環(huán)常常也是提煉的信號。對于條件表達(dá)式,可以使用  分解條件表達(dá)式(Decompose Conditional)  。至于循環(huán),應(yīng)該使用  提煉函數(shù)(Extract Method)  將循環(huán)和其內(nèi)的代碼提煉到獨(dú)立函數(shù)中。

收益

  • 在所有類型的面向?qū)ο蟠a中,函數(shù)比較短小精悍的類往往生命周期較長。一個函數(shù)越長,就越不容易理解和維護(hù)。
  • 此外,過長函數(shù)中往往含有難以發(fā)現(xiàn)的重復(fù)代碼。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

性能

是否像許多人說的那樣,增加函數(shù)的數(shù)量會影響性能?在幾乎絕大多數(shù)情況下,這種影響是可以忽略不計(jì),所以不用擔(dān)心。 此外,現(xiàn)在有了清晰和易讀的代碼,在需要的時候,你將更容易找到真正有效的函數(shù)來重組代碼和提高性能。

重構(gòu)方法說明

提煉函數(shù)(Extract Method)

問題

你有一段代碼可以組織在一起。

void printOwing() {
  printBanner();
  //print details
  System.out.println("name: " + name);
  System.out.println("amount: " + getOutstanding());
}

解決

移動這段代碼到一個新的函數(shù)中,使用函數(shù)的調(diào)用來替代老代碼。

void printOwing() {
  printBanner();
  printDetails(getOutstanding());
}
void printDetails(double outstanding) {
  System.out.println("name: " + name);
  System.out.println("amount: " + outstanding);
}

以查詢?nèi)〈R時變量(Replace Temp with Query)

問題

將表達(dá)式的結(jié)果放在局部變量中,然后在代碼中使用。

double calculateTotal() {
  double basePrice = quantity * itemPrice;
  if (basePrice > 1000) {
    return basePrice * 0.95;
  }
  else {
    return basePrice * 0.98;
  }
}

解決

將整個表達(dá)式移動到一個獨(dú)立的函數(shù)中并返回結(jié)果。使用查詢函數(shù)來替代使用變量。如果需要,可以在其他函數(shù)中合并新函數(shù)。

double calculateTotal() {
  double basePrice = quantity * itemPrice;
  if (basePrice > 1000) {
    return basePrice * 0.95;
  }
  else {
    return basePrice * 0.98;
  }
}

引入?yún)?shù)對象(Introduce Parameter Object)

問題

某些參數(shù)總是很自然地同時出現(xiàn)。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

解決

以一個對象來取代這些參數(shù)。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

保持對象完整(Preserve Whole Object)

問題

你從某個對象中取出若干值,將它們作為某一次函數(shù)調(diào)用時的參數(shù)。

int low = daysTempRange.getLow();
int high = daysTempRange.getHigh();
boolean withinPlan = plan.withinRange(low, high);

解決

改為傳遞整個對象。

boolean withinPlan = plan.withinRange(daysTempRange);

以函數(shù)對象取代函數(shù)(Replace Method with Method Object)

問題

你有一個過長函數(shù),它的局部變量交織在一起,以致于你無法應(yīng)用提煉函數(shù)(Extract Method) 。

class Order {
  //...
  public double price() {
    double primaryBasePrice;
    double secondaryBasePrice;
    double tertiaryBasePrice;
    // long computation.
    //...
  }
}

解決

將函數(shù)移到一個獨(dú)立的類中,使得局部變量成了這個類的字段。然后,你可以將函數(shù)分割成這個類中的多個函數(shù)。

class Order {
  //...
  public double price() {
    return new PriceCalculator(this).compute();
  }
}
class PriceCalculator {
  private double primaryBasePrice;
  private double secondaryBasePrice;
  private double tertiaryBasePrice;
  public PriceCalculator(Order order) {
    // copy relevant information from order object.
    //...
  }
  public double compute() {
    // long computation.
    //...
  }
}

分解條件表達(dá)式(Decompose Conditional)

問題

你有復(fù)雜的條件表達(dá)式。

if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
  charge = quantity * winterRate + winterServiceCharge;
}
else {
  charge = quantity * summerRate;
}

解決

根據(jù)條件分支將整個條件表達(dá)式分解成幾個函數(shù)。

if (notSummer(date)) {
  charge = winterCharge(quantity);
}
else {
  charge = summerCharge(quantity);
}

過長參數(shù)列

過長參數(shù)列(Long Parameter List)

一個函數(shù)有超過 3、4 個入?yún)ⅰ?/p>

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

問題原因

過長參數(shù)列可能是將多個算法并到一個函數(shù)中時發(fā)生的。函數(shù)中的入?yún)⒖梢杂脕砜刂谱罱K選用哪個算法去執(zhí)行。

過長參數(shù)列也可能是解耦類之間依賴關(guān)系時的副產(chǎn)品。例如,用于創(chuàng)建函數(shù)中所需的特定對象的代碼已從函數(shù)移動到調(diào)用函數(shù)的代碼處,但創(chuàng)建的對象是作為參數(shù)傳遞到函數(shù)中。因此,原始類不再知道對象之間的關(guān)系,并且依賴性也已經(jīng)減少。但是如果創(chuàng)建的這些對象,每一個都將需要它自己的參數(shù),這意味著過長參數(shù)列。

太長的參數(shù)列難以理解,太多參數(shù)會造成前后不一致、不易使用,而且一旦需要更多數(shù)據(jù),就不得不修改它。

解決方案

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

 

  • 如果向已有的對象發(fā)出一條請求就可以取代一個參數(shù),那么你應(yīng)該使用  以函數(shù)取代參數(shù)(Replace Parameter with Methods)  。在這里,,“已有的對象”可能是函數(shù)所屬類里的一個字段,也可能是另一個參數(shù)。
  • 你還可以運(yùn)用  保持對象完整(Preserve Whole Object)  將來自同一對象的一堆數(shù)據(jù)收集起來,并以該對象替換它們。
  • 如果某些數(shù)據(jù)缺乏合理的對象歸屬,可使用  引入?yún)?shù)對象(Introduce Parameter Object)  為它們制造出一個“參數(shù)對象”。

收益

  • 更易讀,更簡短的代碼。
  • 重構(gòu)可能會暴露出之前未注意到的重復(fù)代碼。

何時忽略

  • 這里有一個重要的例外:有時候你明顯不想造成"被調(diào)用對象"與"較大對象"間的某種依賴關(guān)系。這時候?qū)?shù)據(jù)從對象中拆解出來單獨(dú)作為參數(shù),也很合情理。但是請注意其所引發(fā)的代價。如果參數(shù)列太長或變化太頻繁,就需要重新考慮自己的依賴結(jié)構(gòu)了。

重構(gòu)方法說明

以函數(shù)取代參數(shù)(Replace Parameter with Methods)

問題

對象調(diào)用某個函數(shù),并將所得結(jié)果作為參數(shù),傳遞給另一個函數(shù)。而接受該參數(shù)的函數(shù)本身也能夠調(diào)用前一個函數(shù)。

int basePrice = quantity * itemPrice;
double seasonDiscount = this.getSeasonalDiscount();
double fees = this.getFees();
double finalPrice = discountedPrice(basePrice, seasonDiscount, fees);

解決

讓參數(shù)接受者去除該項(xiàng)參數(shù),并直接調(diào)用前一個函數(shù)。

int basePrice = quantity * itemPrice;
double finalPrice = discountedPrice(basePrice);

保持對象完整(Preserve Whole Object)

問題

你從某個對象中取出若干值,將它們作為某一次函數(shù)調(diào)用時的參數(shù)。

int low = daysTempRange.getLow();
int high = daysTempRange.getHigh();
boolean withinPlan = plan.withinRange(low, high);

解決

改為傳遞整個對象。

boolean withinPlan = plan.withinRange(daysTempRange);

引入?yún)?shù)對象(Introduce Parameter Object)

問題

某些參數(shù)總是很自然地同時出現(xiàn)。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

解決

以一個對象來取代這些參數(shù)。

怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅

當(dāng)前名稱:怎么讓代碼不再臃腫,寫的像詩一樣優(yōu)雅-創(chuàng)新互聯(lián)
鏈接URL:http://www.muchs.cn/article38/pccpp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開發(fā)、關(guān)鍵詞優(yōu)化自適應(yīng)網(wǎng)站、微信公眾號、域名注冊搜索引擎優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)