国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

《重構(gòu)---改善既有代碼的設(shè)計(jì)》之在對(duì)象之間搬移特性

BlackHole1 / 1943人閱讀

摘要:本篇文章主要講解重構(gòu)改善既有代碼的設(shè)計(jì)這本書(shū)中的第七章在對(duì)象之間搬移特性中的知識(shí)點(diǎn),搬移函數(shù)問(wèn)題你的程序中,有個(gè)函數(shù)與其所駐之外的另一個(gè)進(jìn)行更多交流調(diào)用后者,或被后者調(diào)用。動(dòng)機(jī)在之間移動(dòng)狀態(tài)和行為,是重構(gòu)過(guò)程中必不可少的措施。

如果你注定要成為厲害的人, 那問(wèn)題的答案就深藏在你的血脈里。

本篇文章主要講解 《重構(gòu)---改善既有代碼的設(shè)計(jì)》 這本書(shū)中的 第七章在對(duì)象之間搬移特性中 的知識(shí)點(diǎn),

Move Method(搬移函數(shù))

問(wèn)題:你的程序中,有個(gè)函數(shù)與其所駐class之外的另一個(gè)class進(jìn)行更多交流:調(diào)用后者,或被后者調(diào)用。

解決:在該函數(shù)最常引用的class中建立一個(gè)有著類(lèi)似行為的新函數(shù)。將舊函數(shù)變成一個(gè)單純的委托函數(shù)(delegating method),或是將舊函數(shù)完全移除。

動(dòng)機(jī)

「函數(shù)搬移」是重構(gòu)理論的支柱。如果一個(gè)class有太多行為,或如果一個(gè)class與另一個(gè)class有太多合作而形成高度耦合(highly coupled),我就會(huì)搬移函數(shù)。通過(guò)這種手段,我可以使系統(tǒng)中的classes更簡(jiǎn)單,這些classes最終也將更干凈利落地實(shí)現(xiàn)系統(tǒng)交付的任務(wù)。
常常我會(huì)瀏覽class的所有函數(shù),從中尋找這樣的函數(shù):使用另一個(gè)對(duì)象的次數(shù)比使用自己所駐對(duì)象的次數(shù)還多。一旦我移動(dòng)了一些值域,就該做這樣的檢查。一旦發(fā)現(xiàn)「有可能被我搬移」的函數(shù),我就會(huì)觀察調(diào)用它的那一端、它調(diào)用的那一端,以及繼承體系中它的任何一個(gè)重定義函數(shù)。然后,我會(huì)根據(jù)「這個(gè)函數(shù)與哪個(gè)對(duì)象的交流比較多」,決定其移動(dòng)路徑。
這往往不是一個(gè)容易做出的決定。如果不能肯定是否應(yīng)該移動(dòng)一個(gè)函數(shù),我就會(huì)繼續(xù)觀察其他函數(shù)。移動(dòng)其他函數(shù)往往會(huì)讓這項(xiàng)決定變得容易一些。有時(shí)候,即使你移動(dòng)了其他函數(shù),還是很難對(duì)眼下這個(gè)函數(shù)做出決定。其實(shí)這也沒(méi)什么大不了的。 如果真的很難做出決定,那么或許「移動(dòng)這個(gè)函數(shù)與否」并不那么重要。所以,我會(huì)憑本能去做,反正以后總是可以修改的。

作法

檢查source class定義之source method所使用的一切特性(features),考慮它們是否也該被搬移。(譯注:此處所謂特性泛指class定義的所有東西,包括值域和函數(shù)。)

如果某個(gè)特性只被你打算搬移的那個(gè)函數(shù)用到,你應(yīng)該將它一并搬移。如果另有其他函數(shù)使用了這個(gè)特性,你可以考慮將使用該特性的所有函數(shù)全都一并搬移。有時(shí)候搬移一組函數(shù)比逐一搬移簡(jiǎn)單些。

范例

我用一個(gè)表示「帳戶(hù)」的account class來(lái)說(shuō)明這項(xiàng)重構(gòu):

class Account...
    //用戶(hù)類(lèi)型類(lèi)
    private AccountType _type;
    //透支天數(shù)
    private int _daysOverdrawn;

  //透支費(fèi)用
  double overdraftCharge() {                //譯注:透支金計(jì)費(fèi),它和其他class的關(guān)系似乎比較密切。
      //判斷保險(xiǎn)
      if (_type.isPremium()) {
          double result = 10;
          if (_daysOverdrawn > 7) result += (_daysOverdrawn - 7) * 0.85;
          return result;
      }
      else return _daysOverdrawn * 1.75;
  }
  //銀行操作
  double bankCharge() {
      double result = 4.5;
      if (_daysOverdrawn > 0) result += overdraftCharge();
      return result;
  }
  

假設(shè)有數(shù)種新帳戶(hù),每一種都有自己的「透支金計(jì)費(fèi)規(guī)則」。
所以我希望將overdraftCharge()搬移到AccountType class去。
第一步要做的是:觀察被overdraftCharge()使用的每一特性(features),考慮是否值得將它們與overdraftCharge()—起移動(dòng)。此例之中我需要讓daysOverdrawn值域留在Account class,因?yàn)槠渲禃?huì)隨不同種類(lèi)的帳戶(hù)而變化。然后,我將overdraftCharge()函數(shù)碼拷貝到AccountType中,并做相應(yīng)調(diào)整。

class AccountType...
  double overdraftCharge(int daysOverdrawn) {
      if (isPremium()) {
          double result = 10;
          if (daysOverdrawn > 7) result += (daysOverdrawn - 7) * 0.85;
          return result;
      }
      else return daysOverdrawn * 1.75;
  }

在這個(gè)例子中,「調(diào)整」的意思是:(1)對(duì)于「使用AccountType特性」的語(yǔ)句,去掉_type;(2)想辦法得到依舊需要的Account class特性。當(dāng)我需要使用source class特性,我有四種選擇:(1)將這個(gè)特性也移到target class;(2)建立或使用一個(gè)從target class到source的引用〔指涉)關(guān)系;(3)將source object當(dāng)作參數(shù)傳給target class;(4)如果所需特性是個(gè)變量,將它當(dāng)作參數(shù)傳給target method。
本例中我將_daysOverdrawn變量作為參數(shù)傳給target method(上述(4))。
調(diào)整target method使之通過(guò)編譯,而后我就可以將source method的函數(shù)本體替換為一個(gè)簡(jiǎn)單的委托動(dòng)作(delegation),然后編譯并測(cè)試:

class Account...
  double overdraftCharge() {
      return _type.overdraftCharge(_daysOverdrawn);
  }

我可以保留代碼如今的樣子,也可以刪除source method。如果決定刪除,就得找出source method的所有調(diào)用者,并將這些調(diào)用重新定向,改調(diào)用Account的bankCharge():

class Account...
  double bankCharge() {
      double result = 4.5;
      if (_daysOverdrawn > 0) result += _type.overdraftCharge(_daysOverdrawn);
      return result;
  }

所有調(diào)用點(diǎn)都修改完畢后,我就可以刪除source method在Account中的聲明了。我可以在每次刪除之后編譯并測(cè)試,也可以一次性批量完成。如果被搬移的函數(shù)不是private,我還需要檢查其他classes是否使用了這個(gè)函數(shù)。在強(qiáng)型(strongly typed) 語(yǔ)言中,刪除source method聲明式后,編譯器會(huì)幫我發(fā)現(xiàn)任何遺漏。
此例之中被移函數(shù)只取用(指涉〕一個(gè)值域,所以我只需將這個(gè)值域作為參數(shù)傳給target method就行了。如果被移函數(shù)調(diào)用了Account中的另一個(gè)函數(shù),我就不能這么簡(jiǎn)單地處理。這種情況下我必須將source object傳遞給target method:

class AccountType...
  double overdraftCharge(Account account) {
      if (isPremium()) {
          double result = 10;
          if (account.getDaysOverdrawn() > 7)
             result += (account.getDaysOverdrawn() - 7) * 0.85;
          return result;
      }
      else return account.getDaysOverdrawn() * 1.75;
  }

如果我需要source class的多個(gè)特性,那么我也會(huì)將source object傳遞給target method。不過(guò)如果target method需要太多source class特性,就得進(jìn)一步重構(gòu)。通常這種情況下我會(huì)分解target method,并將其中一部分移回source class。

Move Field(搬移值域)

問(wèn)題:你的程序中,某個(gè)field(值域〕被其所駐class之外的另一個(gè)class更多地用到。
解決:在target class 建立一個(gè)new field,修改source field的所有用戶(hù),令它們改用此new field。

動(dòng)機(jī)

在classes之間移動(dòng)狀態(tài)(states)和行為,是重構(gòu)過(guò)程中必不可少的措施。
隨著系統(tǒng)發(fā)展,你會(huì)發(fā)現(xiàn)自己需要新的class,并需要將原本的工作責(zé)任拖到新的class中。這個(gè)星期中合理而正確的設(shè)計(jì)決策,到了下個(gè)星期可能不再正確。這沒(méi)問(wèn)題;如果你從來(lái)沒(méi)遇到這種情況,那才有問(wèn)題。
如果我發(fā)現(xiàn),對(duì)于一個(gè)field(值域),在其所駐class之外的另一個(gè)class中有更多函數(shù)使用了它,我就會(huì)考慮搬移這個(gè)field。上述所謂「使用」可能是通過(guò)設(shè)值/取值(setting/getting)函數(shù)間接進(jìn)行。我也可能移動(dòng)該field的用戶(hù)(某函數(shù)),這取決于是否需要保持接口不受變化。
如果這些函數(shù)看上去很適合待在原地,我就選擇搬移field。
使用Extract Class 時(shí),我也可能需要搬移field。此時(shí)我會(huì)先搬移field,然后再搬移函數(shù)。

作法

如果field的屬性是public,首先使用Encapsulate Field(封裝字段) 將它封裝起來(lái)。
? 如果你有可能移動(dòng)那些頻繁訪問(wèn)該field的函數(shù),或如果有許多函數(shù)訪問(wèn)某個(gè)field,先使用Self Encapsulate Field 也許會(huì)有幫助。

編譯,測(cè)試。

在target class中建立與source field相同的field,并同時(shí)建立相應(yīng)的設(shè)值/取值 (setting/getting)函數(shù)。

編譯target class。

決定如何在source object中引用target object。
? 一個(gè)現(xiàn)成的field或method可以助你得到target object。如果沒(méi)有,就看能否輕易建立這樣一個(gè)函數(shù)。如果還不行,就得在source class中新建一個(gè)field來(lái)存放target object。這可能是個(gè)永久性修改,但你也可以暫不公開(kāi)它,因?yàn)楹罄m(xù)重構(gòu)可能會(huì)把這個(gè)新建field除掉。

刪除source field。

將所有「對(duì)source field的引用」替換為「對(duì)target適當(dāng)函數(shù)的調(diào)用」。
? 如果是「讀取」該變量,就把「對(duì)source field的引用」替換為「對(duì)target取值函數(shù)(getter)的調(diào)用」;如果是「賦值」該變量,就把對(duì)source field的引用」替換成「對(duì)設(shè)值函數(shù)(setter)的調(diào)用」。
? 如果source field不是private,就必須在source class的所有subclasses中查找source field的引用點(diǎn),并進(jìn)行相應(yīng)替換。

· 編譯,測(cè)試。

范例

下面是Account class的部分代碼:

class Account...
  private AccountType _type;
  private double _interestRate;
  double interestForAmount_days (double amount, int days) {
      return _interestRate * amount * days / 365;
  }

我想把表示利率的_interestRate搬移到AccountType class去。
目前已有數(shù)個(gè)函數(shù)引用了它,interestForAmount_days() 就是其一。
下一步我要在AccountType中建立_interestRate field以及相應(yīng)的訪問(wèn)函數(shù):

class AccountType...
  private double _interestRate;
  void setInterestRate (double arg) {
      _interestRate = arg;
  }
  double getInterestRate () {
      return _interestRate;
  }

這時(shí)候我可以編譯新的AccountType class。
現(xiàn)在,我需要讓Account class中訪問(wèn)此_interestRate field的函數(shù)轉(zhuǎn)而使用AccountType對(duì)象,然后刪除Account class中的_interestRate field。
我必須刪除source field,才能保證其訪問(wèn)函數(shù)的確改變了操作對(duì)象,因?yàn)榫幾g器會(huì)幫我指出未正確獲得修改的函數(shù)。

  private double _interestRate;
  double interestForAmount_days (double amount, int days) {
      return _type.getInterestRate() * amount * days / 365;
  }
范例:使用Self Encapsulate(自我封裝)

如果有很多函數(shù)已經(jīng)使用了_interestRate field,我應(yīng)該先運(yùn)用Self Encapsulate Field:

class Account...
   private AccountType _type;
   private double _interestRate;
   double interestForAmount_days (double amount, int days) {
       return getInterestRate() * amount * days / 365;
   }
   private void setInterestRate (double arg) {
       _interestRate = arg;
   }
   private double getInterestRate () {
       return _interestRate;
   }

這樣,在搬移field之后,我就只需要修改訪問(wèn)函數(shù)(accessors)就行了 :

   double interestForAmountAndDays (double amount, int days) {
       return getInterestRate() * amount * days / 365;
   }
   private void setInterestRate (double arg) {
      _type.setInterestRate(arg);
   }
   private double getInterestRate () {
       return _type.getInterestRate();
   }

如果以后有必要,我可以修改訪問(wèn)函數(shù)(accessors)的用戶(hù),讓它們使用新對(duì)象。 Self Encapsulate Field 使我得以保持小步前進(jìn)。如果我需要對(duì)做許多處理,保持小步前進(jìn)是有幫助的。特別值得一提的是:首先使用Self Encapsulate Field 使我得以更輕松使用Move Method 將函數(shù)搬移到target class中。如果待移函數(shù)引用了field的訪問(wèn)函數(shù)(accessors),那么那些引用點(diǎn)是無(wú)須修 改的。

Extract Class(提煉類(lèi))

問(wèn)題:某個(gè)class做了應(yīng)該由兩個(gè)classes做的事。

解決:建立一個(gè)新class,將相關(guān)的值域和函數(shù)從舊class搬移到新class。

動(dòng)機(jī)

你也許聽(tīng)過(guò)類(lèi)似這樣的教誨:一個(gè)class應(yīng)該是一個(gè)清楚的抽象(abstract),處理一些明確的責(zé)任。
但是在實(shí)際工作中,class會(huì)不斷成長(zhǎng)擴(kuò)展。你會(huì)在這兒加入一些功能,在那兒加入一些數(shù)據(jù)。給某個(gè)class添加一項(xiàng)新責(zé)任時(shí),你會(huì)覺(jué)得不值得為這項(xiàng)責(zé)任分離出一個(gè)多帶帶的class。于是,隨著責(zé)任不斷増加,這個(gè)class會(huì)變得過(guò)份復(fù)雜。很快,你的class就會(huì)變成一團(tuán)亂麻。
這樣的class往往含有大量函數(shù)和數(shù)據(jù)。這樣的class往往太大而不易理解。此時(shí)你需要考慮哪些部分可以分離出去,并將它們分離到一個(gè)多帶帶的class中。如果某些數(shù)據(jù)和某些函數(shù)總是一起出現(xiàn),如果某些數(shù)據(jù)經(jīng)常同時(shí)變化甚至彼此相依,這就表示你應(yīng)該將它們分離出去。一個(gè)有用的測(cè)試就是問(wèn)你自己,如果你搬移了某些值域和函數(shù),會(huì)發(fā)生什么事?其他值域和函數(shù)是否因此變得無(wú)意義?
另一個(gè)往往在開(kāi)發(fā)后期出現(xiàn)的信號(hào)是class的「subtyped方式」。如果你發(fā)現(xiàn)subtyping只影響class的部分特性,或如果你發(fā)現(xiàn)某些特性「需要以此方式subtyped」,某些特性「需要以彼方式subtyped」,這就意味你需要分解原來(lái)的class。

作法

決定如何分解c;ass所負(fù)責(zé)任。

建立一個(gè)新class,用以表現(xiàn)從舊class中分離出來(lái)的責(zé)任。
? 如果舊class剩下的責(zé)任與舊class名稱(chēng)不符,為舊class易名。

建立「從舊class訪問(wèn)新class」的連接關(guān)系(link)。
? 也許你有可能需要一個(gè)雙向連接。但是在真正需要它之前,不要建立 「從新class通往舊class」的連接。

對(duì)于你想搬移的每一個(gè)值域,運(yùn)用Move Field 搬移之。

每次搬移后,編譯、測(cè)試。

使用Move Method 將必要函數(shù)搬移到新class。先搬移較低層函數(shù)(也就是「被其他函數(shù)調(diào)用」多于「調(diào)用其他函數(shù)」者),再搬移較高層函數(shù)。

每次搬移之后,編譯、測(cè)試。

檢查,精簡(jiǎn)每個(gè)class的接口。
? 如果你建立起雙向連接,檢查是否可以將它改為單向連接。

決定是否讓新class曝光。如果你的確需要曝光它,決定讓它成為reference object (引用型對(duì)象〕或immutable value object(不可變之「實(shí)值型對(duì)象」)。

范例

讓我們從一個(gè)簡(jiǎn)單的Person class開(kāi)始

class Person...

   private String _name;
   private String _officeAreaCode;
   private String _officeNumber;


   public String getName() {
       return _name;
   }
   public String getTelephoneNumber() {
       return ("(" + _officeAreaCode + ") " + _officeNumber);
   }
   String getOfficeAreaCode() {
       return _officeAreaCode;
   }
   void setOfficeAreaCode(String arg) {
       _officeAreaCode = arg;
   }
   String getOfficeNumber() {
       return _officeNumber;
   }
   void setOfficeNumber(String arg) {
       _officeNumber = arg;
   }
   

在這個(gè)例子中,我可以將「與電話(huà)號(hào)碼相關(guān)」的行為分離到一個(gè)獨(dú)立class中。首 先我耍定義一個(gè)TelephoneNumber class來(lái)表示「電話(huà)號(hào)碼」這個(gè)概念:

class TelephoneNumber {
}

易如反掌!然后,我要建立從Person到TelephoneNumber的連接:

class Person
   private TelephoneNumber _officeTelephone = new TelephoneNumber();

現(xiàn)在,我運(yùn)用Move Field 移動(dòng)一個(gè)值域:

class Person...
   public String getName() {
       return _name;
   }
   public String getTelephoneNumber(){
       return _officeTelephone.getTelephoneNumber();
   }
   TelephoneNumber getOfficeTelephone() {
       return _officeTelephone;
   }
   private String _name;
   private TelephoneNumber _officeTelephone = new TelephoneNumber();
class TelephoneNumber...
   public String getTelephoneNumber() {
       return ("(" + _areaCode + ") " + _number);
   }
   String getAreaCode() {
       return _areaCode;
   }
   void setAreaCode(String arg) {
       _areaCode = arg;
   }
   String getNumber() {
       return _number;
   }
   void setNumber(String arg) {
       _number = arg;
   }
   private String _number;
   private String _areaCode;

下一步要做的決定是:要不要對(duì)客戶(hù)揭示這個(gè)新口class?我可以將Person中「與電 話(huà)號(hào)碼相關(guān)」的函數(shù)委托(delegating)至TelephoneNumber,從而完全隱藏這個(gè)新class;也可以直接將它對(duì)用戶(hù)曝光。我還可以將它暴露給部分用戶(hù)(位于同一個(gè)package中的用戶(hù)),而不暴露給其他用戶(hù)。
如果我選擇暴露新class,我就需要考慮別名(aliasing)帶來(lái)的危險(xiǎn)。如果我暴露了TelephoneNumber ,而有個(gè)用戶(hù)修改了對(duì)象中的_areaCode值域值,我又怎么能知道呢?而且,做出修改的可能不是直接用戶(hù),而是用戶(hù)的用戶(hù)的用戶(hù)。
面對(duì)這個(gè)問(wèn)題,我有下列數(shù)種選擇:

允許任何對(duì)象修改TelephoneNumber 對(duì)象的任何部分。這就使得TelephoneNumber 對(duì)象成為引用對(duì)象(reference object),于是我應(yīng)該考慮使用 Change Value to Reference。這種情況下,Person應(yīng)該是TelephoneNumber的訪問(wèn)點(diǎn)。

不許任何人「不通過(guò)Person對(duì)象就修改TelephoneNumber 對(duì)象」。為了達(dá)到目的,我可以將TelephoneNumber「設(shè)為不可修改的(immutable),或?yàn)樗峁┮粋€(gè)不可修改的接口(immutable interface)。

另一個(gè)辦法是:先復(fù)制一個(gè)TelephoneNumber 對(duì)象,然后將復(fù)制得到的新對(duì)象傳遞給用戶(hù)。但這可能會(huì)造成一定程度的迷惑,因?yàn)槿藗儠?huì)認(rèn)為他們可以修改TelephoneNumber對(duì)象值。此外,如果同一個(gè)TelephoneNumber 對(duì)象 被傳遞給多個(gè)用戶(hù),也可能在用戶(hù)之間造成別名(aliasing)問(wèn)題。

Extract Class 是改善并發(fā)(concurrent)程序的一種常用技術(shù),因?yàn)樗鼓憧梢詾樘釤捄蟮膬蓚€(gè)classes分別加鎖(locks)。如果你不需要同時(shí)鎖定兩個(gè)對(duì)象, 你就不必這樣做。這方面的更多信息請(qǐng)看Lea[Lea], 3.3節(jié)。
這里也存在危險(xiǎn)性。如果需要確保兩個(gè)對(duì)象被同時(shí)鎖定,你就面臨事務(wù)(transaction)問(wèn)題,需要使用其他類(lèi)型的共享鎖〔shared locks〕。正如Lea[Lea] 8.1節(jié)所討論, 這是一個(gè)復(fù)雜領(lǐng)域,比起一般情況需要更繁重的機(jī)制。事務(wù)(transaction)很有實(shí)用性,但是編寫(xiě)事務(wù)管理程序(transaction manager)則超出了大多數(shù)程序員的職責(zé)范圍。

Inline Class(將類(lèi)內(nèi)聯(lián)化)

問(wèn)題:你的某個(gè)class沒(méi)有做太多事情(沒(méi)有承擔(dān)足夠責(zé)任)。

解決:將class的所有特性搬移到另一個(gè)class中,然后移除原class。

動(dòng)機(jī)

Inline Class正好與Extract Class 相反。如果一個(gè)class不再承擔(dān)足夠 責(zé)任、不再有多帶帶存在的理由〔這通常是因?yàn)榇饲暗闹貥?gòu)動(dòng)作移走了這個(gè)class的 責(zé)任),我就會(huì)挑選這一「萎縮class」的最頻繁用戶(hù)(也是個(gè)class),以Inline Class手法將「妻縮class」塞進(jìn)去。

作法

在absorbing class(合并端的那個(gè)class)身上聲明source class的public協(xié)議, 并將其中所有函數(shù)委托(delegate)至source class。
? 如果「以一個(gè)獨(dú)立接口表示source class函數(shù)」更合適的話(huà),就應(yīng)該在inlining之前先使用Extract Interface。

修改所有source class引用點(diǎn),改而引用absorbing class。
? 將source class聲明為private,以斬?cái)鄍ackage之外的所有引用可能。 同時(shí)并修改source class的名稱(chēng),這便可使編譯器幫助你捕捉到所有對(duì)于source class的"dangling references "(虛懸引用點(diǎn))。

編譯,測(cè)試。

運(yùn)用Move Method 和 Move Field ,將source class的特性全部搬移至absorbing class。

為source class舉行一個(gè)簡(jiǎn)單的喪禮。

范例

先前(上個(gè)重構(gòu)項(xiàng)〉我從TelephoneNumber「提煉出另一個(gè)class,現(xiàn)在我要將它inlining塞回到Person去。一開(kāi)始這兩個(gè)classes是分離的:

class Person...


   private String _number;
   private String _areaCode;

   public String getName() {
       return _name;
   }
   public String getTelephoneNumber(){
       return _officeTelephone.getTelephoneNumber();
   }
   TelephoneNumber getOfficeTelephone() {
       return _officeTelephone;
   }
   private String _name;
   private TelephoneNumber _officeTelephone = new TelephoneNumber();
class TelephoneNumber...
   public String getTelephoneNumber() {
       return ("(" + _areaCode + ") " + _number);
   }
   String getAreaCode() {
       return _areaCode;
   }
   void setAreaCode(String arg) {
       _areaCode = arg;
   }
   String getNumber() {
       return _number;
   }
   void setNumber(String arg) {
       _number = arg;
   }

首先我在Person中聲明TelephoneNumber「的所有「可見(jiàn)」(public)函數(shù):

class Person...
   String getAreaCode() {
       return _officeTelephone.getAreaCode();        //譯注:請(qǐng)注意其變化
   }
   void setAreaCode(String arg) {
       _officeTelephone.setAreaCode(arg);                //譯注:請(qǐng)注意其變化
   }
   String getNumber() {
       return _officeTelephone.getNumber();        //譯注:請(qǐng)注意其變化
   }
   void setNumber(String arg) {
       _officeTelephone.setNumber(arg);                //譯注:請(qǐng)注意其變化
   }

現(xiàn)在,我要找出TelephoneNumber的所有用戶(hù),讓它們轉(zhuǎn)而使用Person接口。于是下列代碼:

  Person martin = new Person();
  martin.getOfficeTelephone().setAreaCode ("781");

就變成了:

       Person martin = new Person();
       martin.setAreaCode ("781");

現(xiàn)在,我可以持續(xù)使用Move Method 和 Move Field ,直到TelephoneNumber不復(fù)存在。

Hide Delegate(隱藏「委托關(guān)系」)

問(wèn)題:客戶(hù)直接調(diào)用其server object(服務(wù)對(duì)象)的delegate class。

解決:在server端(某個(gè)class〕建立客戶(hù)所需的所有函數(shù),用以隱藏委托關(guān)系(delegation)。

動(dòng)機(jī)

封裝」即使不是對(duì)象的最關(guān)鍵特征,也是最關(guān)鍵特征之一。「封裝」意味每個(gè)對(duì)象都應(yīng)該盡可能少了解系統(tǒng)的其他部分。如此一來(lái),一旦發(fā)生變化,需要了解這一 變化的對(duì)象就會(huì)比較少——這會(huì)使變化比較容易進(jìn)行。
任何學(xué)過(guò)對(duì)象技術(shù)的人都知道:雖然Java允許你將值域聲明為public,但你還是應(yīng)該隱藏對(duì)象的值域。隨著經(jīng)驗(yàn)日漸豐富,你會(huì)發(fā)現(xiàn),有更多可以(并值得)封裝的東西。
如果某個(gè)客戶(hù)調(diào)用了「建立于server object (服務(wù)對(duì)象)的某個(gè)值域基礎(chǔ)之上」的函數(shù),那么客戶(hù)就必須知曉這一委托對(duì)象(delegate object。譯注:即server object的那個(gè)特殊值域)。萬(wàn)一委托關(guān)系發(fā)生變化,客戶(hù)也得相應(yīng)變化。你可以在server 端放置一個(gè)簡(jiǎn)單的委托函數(shù)(delegating method),將委托關(guān)系隱藏起來(lái),從而去除這種依存性(圖7.1)。這么一來(lái)即便將來(lái)發(fā)生委托關(guān)系上的變化,變化將被限制在server中,不會(huì)波及客戶(hù)。

對(duì)于某些客戶(hù)或全部客戶(hù),你可能會(huì)發(fā)現(xiàn),有必要先使用Extract Class 。一旦你對(duì)所有客戶(hù)都隱藏委托關(guān)系(delegation),你就可以將server 接口中的所有 委托都移除。

作法

對(duì)于每一個(gè)委托關(guān)系中的函數(shù),在server端建立一個(gè)簡(jiǎn)單的委托函數(shù)(delegating method)。

調(diào)整客戶(hù),令它只調(diào)用server 提供的函數(shù)(譯注:不得跳過(guò)徑自調(diào)用下層)。
? 如果client (客戶(hù)〕和server不在同一個(gè)package,考慮修改委托函數(shù) (delegate method)的訪問(wèn)權(quán)限,讓client得以在package之外調(diào)用它。

每次調(diào)整后,編譯并測(cè)試。

如果將來(lái)不再有任何客戶(hù)需要取用圖7.1的Delegate (受托類(lèi)),便可移除server中的相關(guān)訪問(wèn)函數(shù)(accessor for the delegate)。

編譯,測(cè)試。

范例

本例從兩個(gè)classes開(kāi)始,代表「人」的Person和代表「部門(mén)」的Department:

class Person {
   Department _department;
   public Department getDepartment() {
       return _department;
   }
   public void setDepartment(Department arg) {
       _department = arg;
   }
}
class Department {
   private String _chargeCode;
   private Person _manager;
   public Department (Person manager) {
       _manager = manager;
   }
   public Person getManager() {
       return _manager;
   }
...

如果客戶(hù)希望知道某人的經(jīng)理是誰(shuí),他必須先取得Department對(duì)象:

manager = john.getDepartment().getManager();


這樣的編碼就是對(duì)客戶(hù)揭露了Department的工作原理,于是客戶(hù)知道:Department用以追蹤「經(jīng)理」這條信息。
如果對(duì)客戶(hù)隱藏Department,可以減少耦合(coupling)。 為了這一目的,我在Person中建立一個(gè)簡(jiǎn)單的委托函數(shù):

   public Person getManager() {
       return _department.getManager();
   }

現(xiàn)在,我得修改Person的所有客戶(hù),讓它們改用新函數(shù):

manager = john.getManager();

只要完成了對(duì)Department所有函數(shù)的委托關(guān)系,并相應(yīng)修改了Person的所有客 戶(hù),我就可以移除Person中的訪問(wèn)函數(shù)getDepartment()了。

Remove Middle Man(移除中間人)

問(wèn)題:某個(gè)class做了過(guò)多的簡(jiǎn)單委托動(dòng)作(simple delegation)。

解決:讓客戶(hù)直接調(diào)用delegate(受托類(lèi))。

動(dòng)機(jī)

在Hide Delegate的「動(dòng)機(jī)」欄,我談到了「封裝 delegated object(受托對(duì) 象)」的好處。
但是這層封裝也是要付出代價(jià)的,它的代價(jià)就是:每當(dāng)客戶(hù)要使用 delegate(受托類(lèi))的新特性時(shí),你就必須在server 端添加一個(gè)簡(jiǎn)單委托函數(shù)。隨著delegate的特性(功能)愈來(lái)愈多,這一過(guò)程會(huì)讓你痛苦不己。server 完全變成了一 個(gè)「中間人」,此時(shí)你就應(yīng)該讓客戶(hù)直接調(diào)用delegate。
很難說(shuō)什么程度的隱藏才是合適的。還好,有了Hide Delegate和Remove Middle Man,你大可不必操心這個(gè)問(wèn)題,因?yàn)槟憧梢栽谙到y(tǒng)運(yùn)行過(guò)程中不斷進(jìn)行調(diào)整。隨著系統(tǒng)的變化,「合適的隱藏程度」這個(gè)尺度也相應(yīng)改變。六個(gè)月 前恰如其分的封裝,現(xiàn)今可能就顯得笨拙。重構(gòu)的意義就在于:你永遠(yuǎn)不必說(shuō)對(duì)不起——只要把出問(wèn)題的地方修補(bǔ)好就行了。

做法

建立一個(gè)函數(shù),用以取用delegate(受托對(duì)象)。

對(duì)于每個(gè)委托函數(shù)(delegate method),在server中刪除該函數(shù),并將「客戶(hù)對(duì)該函數(shù)的調(diào)用」替換為「對(duì)delegate(受托對(duì)象)的調(diào)用」。

處理每個(gè)委托函數(shù)后,編譯、測(cè)試。

范例

我將以另一種方式使用先前用過(guò)的「人與部門(mén)」例子。還記得嗎,上一項(xiàng)重構(gòu)結(jié)束時(shí),Person將Department隱藏起來(lái)了:

class Person...
   Department _department;       
   public Person getManager() {
       return _department.getManager();
class Department...
   private Person _manager;
   public Department (Person manager) {
       _manager = manager;
   }

為了找出某人的經(jīng)理,客戶(hù)代碼可能這樣寫(xiě):

manager = john.getManager();

像這樣,使用和封裝Department都很簡(jiǎn)單。但如果大量函數(shù)都這么做,我就不得不在Person之中安置大量委托行為(delegations)。這就是移除中間人的時(shí)候了。 首先在Person建立一個(gè)「受托對(duì)象(delegate)取得函數(shù)」:

class Person...
   public Department getDepartment() {
       return _department;
   }

然后逐一處理每個(gè)委托函數(shù)。針對(duì)每一個(gè)這樣的函數(shù),我要找出通過(guò)Person使用的函數(shù),并對(duì)它進(jìn)行修改,使它首先獲得受托對(duì)象(delegate),然后直接使用之:
manager = john.getDepartment().getManager();
然后我就可以刪除Person的getManager() 函數(shù)。如果我遺漏了什么,編譯器會(huì) 告訴我。
為方便起見(jiàn),我也可能想要保留一部分委托關(guān)系(delegations)。此外我也可能希望對(duì)某些客戶(hù)隱藏委托關(guān)系,并讓另一些用戶(hù)直接使用受托對(duì)象。基于這些原因,一些簡(jiǎn)單的委托關(guān)系(以及對(duì)應(yīng)的委托函數(shù))也可能被留在原地。

Introduce Foreign Method(引入外加函數(shù))

問(wèn)題:你所使用的server class需要一個(gè)額外函數(shù),但你無(wú)法修改這個(gè)class。

解決:在client class中建立一個(gè)函數(shù),并以一個(gè)server class實(shí)體作為第一引數(shù)(argument)

 Date newStart = new Date (previousEnd.getYear(),
                    previousEnd.getMonth(), previousEnd.getDate() + 1);
 
    Date newStart = nextDay(previousEnd);
    private static Date nextDay(Date arg) {
        return new Date (arg.getYear(),arg.getMonth(), arg.getDate() + 1);
    }
動(dòng)機(jī)

這種事情發(fā)生過(guò)太多次了:你正在使用一個(gè)class,它真的很好,為你提供了你想要的所有服務(wù)。
而后,你又需要一項(xiàng)新服務(wù),這個(gè)class卻無(wú)法供應(yīng)。
于是你開(kāi)始咒罵:「為什么不能做這件事?」如果可以修改源碼,你便可以自行添加一個(gè)新函數(shù); 如果不能,你就得在客戶(hù)端編碼,補(bǔ)足你要的那個(gè)函數(shù)。
如果client class只使用這項(xiàng)功能一次,那么額外編碼工作沒(méi)什么大不了,甚至可能根本不需要原本提供服務(wù)的那個(gè)class。然而如果你需要多次使用這個(gè)函數(shù),你就得不斷重復(fù)這些代碼。還記得嗎,重復(fù)的代碼是軟件萬(wàn)惡之源。這些重復(fù)性代碼應(yīng)該被抽出來(lái)放進(jìn)同一個(gè)函數(shù)中。進(jìn)行本項(xiàng)重構(gòu)時(shí),如果你以外加函數(shù)實(shí)現(xiàn)一項(xiàng)功能, 那就是一個(gè)明確信號(hào):這個(gè)函數(shù)原本應(yīng)該在提供服務(wù)的(server)class中加以實(shí)現(xiàn)。
如果你發(fā)現(xiàn)自己為一個(gè)server class建立了大量外加函數(shù),或如果你發(fā)現(xiàn)有許多classes都需要同樣的外加函數(shù),你就不應(yīng)該再使用本項(xiàng)重構(gòu),而應(yīng)該使用 Introduce Local Extension。
但是不要忘記:外加函數(shù)終歸是權(quán)宜之計(jì)。如果有可能,你仍然應(yīng)該將這些函數(shù)搬移到它們的理想家園。如果代碼擁有權(quán)(code ownership)是個(gè)需要考量的問(wèn)題, 就把外加函數(shù)交給server class的擁有者,請(qǐng)他幫你在此server class中實(shí)現(xiàn)這個(gè)函數(shù)。

作法

在client class中建立一個(gè)函數(shù),用來(lái)提供你需要的功能。
? 這個(gè)函數(shù)不應(yīng)該取用client class的任何特性。如果它需要一個(gè)值,把該值當(dāng)作參數(shù)傳給它。

以server class實(shí)體作為該函數(shù)的第一個(gè)參數(shù)。

將該函數(shù)注釋為:「外加函數(shù)(foreign method),應(yīng)在server class實(shí)現(xiàn)。」
? 這么一來(lái),將來(lái)如果有機(jī)會(huì)將外加函數(shù)搬移到server class中,你便可以輕松找出這些外加函數(shù)。

范例

程序中,我需要跨過(guò)一個(gè)收費(fèi)周期(billing period)。原本代碼像這樣:

    Date newStart = new Date (previousEnd.getYear(),
         previousEnd.getMonth(), previousEnd.getDate() + 1);

我可以將賦值運(yùn)算右側(cè)代碼提煉到一個(gè)獨(dú)立函數(shù)中。這個(gè)函數(shù)就是Date class的一個(gè)外加函數(shù):

Date newStart = nextDay(previousEnd);
private static Date nextDay(Date arg) {
// foreign method, should be on date
     return new Date (arg.getYear(),arg.getMonth(), arg.getDate() + 1);
}
Introduce Local Extension(引入本地?cái)U(kuò)展)

問(wèn)題:你所使用的server class需要一些額外函數(shù),但你無(wú)法修改這個(gè)class。
解決:建立一個(gè)新class,使它包含這些額外函數(shù)。讓這個(gè)擴(kuò)展品成為source class的subclass (子類(lèi)〕或wrapper(外覆類(lèi))。

動(dòng)機(jī)

很遺憾,classes的作者無(wú)法預(yù)知未來(lái),他們常常沒(méi)能為你預(yù)先準(zhǔn)備一些有用的函數(shù)。
如果你可以修改源碼,最好的辦法就是直接加入自己需要的函數(shù)。但你經(jīng)常無(wú)法修改源碼。如果只需要一兩個(gè)函數(shù),你可以使用Introduce Foreign Method。

但如果你需要的額外函數(shù)超過(guò)兩個(gè),外加函數(shù)(foreign methods)就很難控制住它 們了。所以,你需要將這些函數(shù)組織在一起,放到一個(gè)恰當(dāng)?shù)胤饺ァR_(dá)到這一目 的,標(biāo)準(zhǔn)對(duì)象技術(shù)subclassing和wrapping是顯而易見(jiàn)的辦法。這種情況下我把 subclass 或wrapper稱(chēng)為local extention(本地?cái)U(kuò)展〕。

所謂本地?cái)U(kuò)展是一個(gè)獨(dú)立的class,但也是被擴(kuò)展的子類(lèi)型。這意味它提供original class的一切特性,同時(shí)并額外添加新特性。在任何使用original class的地方,你都可以使用local extention取而代之。

作法

建立一個(gè)extension class,將它作為原物(原類(lèi)〉的subclass或wrapper。

在extension class 中加入轉(zhuǎn)型構(gòu)造函數(shù)(converting constructors )。
? 所謂「轉(zhuǎn)型構(gòu)造函數(shù)」是指接受原物(original)作為參數(shù)。如果你釆用subclassing方案,那么轉(zhuǎn)型構(gòu)造函數(shù)應(yīng)該調(diào)用適當(dāng)?shù)膕ubclass構(gòu)造函數(shù);如果你采用wrapper方案,那么轉(zhuǎn)型構(gòu)造函數(shù)應(yīng)該將它所獲得之引數(shù)(argument)賦值給「用以保存委托關(guān)系(delegate)」的那個(gè)值域。

在extension class中加入新特性。

根據(jù)需要,將原物(original)替換為擴(kuò)展物(extension)。

將「針對(duì)原始類(lèi)(original class)而定義的所有外加函數(shù)(foreign methods)」 搬移到擴(kuò)展類(lèi)extension中。

范例

我將以Java 1.0.1的Date class為例。Java 1.1已經(jīng)提供了我想要的功能,但是在它到來(lái)之前的那段日子,很多時(shí)候我需要擴(kuò)展Java 1.0.1的Date class。
第一件待決事項(xiàng)就是使用subclass或wrapper。subclassing是比較顯而易見(jiàn)的辦法:

Class mfDate extends Date {
   public nextDay()...
   public dayOfYear()...

wrapper則需要用上委托(delegation):

                                  
class mfDate {
   private Date _original;
范例:是用Subclass(子類(lèi))

首先,我要建立一個(gè)新的MfDateSub class來(lái)表示「日期」(譯注:"Mf"是作者M(jìn)artin Fowler的姓名縮寫(xiě)),并使其成為Date的subclass:

  class MfDateSub extends Date

然后,我需要處理Date 和我的extension class之間的不同處。MfDateSub 構(gòu)造函數(shù)需要委托(delegating)給Date構(gòu)造函數(shù):

public MfDateSub (String dateString) {
      super (dateString);
};

現(xiàn)在,我需要加入一個(gè)轉(zhuǎn)型構(gòu)造函數(shù),其參數(shù)是一個(gè)隸屬原類(lèi)的對(duì)象:

  public MfDateSub (Date arg) {
      super (arg.getTime());
  }

現(xiàn)在,我可以在extension class中添加新特性,并使用Move Method 將所有外加函數(shù)(foreign methods)搬移到extension class。于是,下面的代碼:

client class...
    private static Date nextDay(Date arg) {
    // foreign method, should be on date
        return new Date (arg.getYear(),arg.getMonth(), arg.getDate() + 1);
    }

經(jīng)過(guò)搬移之后,就成了:

  class MfDate...
    Date nextDay() {
        return new Date (getYear(),getMonth(), getDate() + 1);
  }
范例:是用wrapper(外覆類(lèi))

首先聲明一個(gè)wrapping class:

  class mfDate {
    private Date _original;
  }

使用wrapping方案時(shí),我對(duì)構(gòu)造函數(shù)的設(shè)定與先前有所不同。現(xiàn)在的構(gòu)造函數(shù)將只是執(zhí)行一個(gè)單純的委托動(dòng)作(delegation):

   public MfDateWrap (String dateString) {
       _original = new Date(dateString);
   };

而轉(zhuǎn)型構(gòu)造函數(shù)則只是對(duì)其instance變量賦值而己:

   public MfDateWrap (Date arg) {
       _original = arg;
   }

接下來(lái)是一項(xiàng)枯燥乏味的工作:為原始類(lèi)的所有函數(shù)提供委托函數(shù)。我只展示兩個(gè)函數(shù),其他函數(shù)的處理依此類(lèi)推。

   public int getYear() {
       return _original.getYear();
   }
   public boolean equals (MfDateWrap arg) {
       return (toDate().equals(arg.toDate()));
   }

完成這項(xiàng)工作之后,我就可以后使用Move Method 將日期相關(guān)行為搬移到新class中。于是以下代碼:

  client class...
    private static Date nextDay(Date arg) {
    // foreign method, should be on date
        return new Date (arg.getYear(),arg.getMonth(), arg.getDate() + 1);
    }

經(jīng)過(guò)搬移之后,就變成:

  class MfDate...
    Date nextDay() {
        return new Date (getYear(),getMonth(), getDate() + 1);
  }

使用wrappers有一個(gè)特殊問(wèn)題:如何處理「接受原始類(lèi)之實(shí)體為參數(shù)」的函數(shù)?例如:

  public boolean after (Date arg)

由于無(wú)法改變?cè)碱?lèi)〔original),所以我只能以一種方式使用上述的after() :

  aWrapper.after(aDate)                         // can be made to work
  aWrapper.after(anotherWrapper)                // can be made to work
  aDate.after(aWrapper)                         // will not work

這樣覆寫(xiě)(overridden)的目的是為了向用戶(hù)隱藏wrapper 的存在。這是一個(gè)好策略,因?yàn)閣rapper 的用戶(hù)的確不應(yīng)該關(guān)心wrapper 的存在,的確應(yīng)該可以同樣地對(duì)待wrapper(外覆類(lèi))和orignal((原始類(lèi))。但是我無(wú)法完全隱藏此一信息,因?yàn)槟承┫到y(tǒng)所提供的函數(shù)(例如equals() 會(huì)出問(wèn)題。
你可能會(huì)認(rèn)為:你可以在MfDateWrap class 中覆寫(xiě)equals(),像這樣:

  public boolean equals (Date arg)     // causes problems

但這樣做是危險(xiǎn)的,因?yàn)楸M管我達(dá)到了自己的目的,Java 系統(tǒng)的其他部分都認(rèn)為equals() 符合交換律:如果a.equals(b)為真,那么b.equals(a)也必為真。違反這一規(guī)則將使我遭遇一大堆莫名其妙的錯(cuò)誤。
要避免這樣的尷尬境地,惟一辦法就是修改Date class。但如果我能夠修改Date ,我又何必進(jìn)行此項(xiàng)重構(gòu)?所以,在這種情況下,我只能(必須〕向用戶(hù)暴露「我進(jìn)行了包裝」這一事實(shí)。我將以一個(gè)新函數(shù)來(lái)進(jìn)行日期之間的相等性檢查(equality tests):

 public boolean equalsDate (Date arg)

我可以重載equalsDate() ,讓一個(gè)重載版本接受Date 對(duì)象,另一個(gè)重載版本接受MfDateWrap 對(duì)象。這樣我就不必檢查未知對(duì)象的型別了:

  public boolean equalsDate (MfDateWrap arg)

subclassing方案中就沒(méi)有這樣的問(wèn)題,只要我不覆寫(xiě)原函數(shù)就行了。
但如果我覆寫(xiě)了original class 中的函數(shù),那么尋找函數(shù)時(shí),我會(huì)被搞得暈頭轉(zhuǎn)向。一般來(lái)說(shuō),我不會(huì)在extension class 中覆寫(xiě)0original class 的函數(shù),我只會(huì)添加新函數(shù)。

譯注:equality(相等性)是一個(gè)很基礎(chǔ)的大題目。《Effective Java》 by Joshua Bloch 第3章,以及《Practical Java》by Peter Haggar 第2章,對(duì)此均有很深入的討論。這兩本書(shū)對(duì)于其他的基礎(chǔ)大題目如Serizable,Comparable,Cloneable,hashCode() 也都有深刻討論。

感謝觀看   你肯定有收獲對(duì)吧

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/70755.html

相關(guān)文章

  • 重構(gòu)-改善既有代碼設(shè)計(jì)(七)-- 在代碼之間搬移特性

    摘要:前言決定把責(zé)任放在哪對(duì)于對(duì)象設(shè)計(jì)是最重要的之一。重構(gòu)可以很好的解決這個(gè)問(wèn)題。方法建立一個(gè)新類(lèi),將相關(guān)的字段和函數(shù)從舊類(lèi)搬移到新類(lèi)。方法將這個(gè)類(lèi)的所有特性搬移到另一個(gè)類(lèi)中,然后移除原類(lèi)。讓這個(gè)擴(kuò)展品成為源類(lèi)的子類(lèi)或包裝類(lèi)。 前言 決定把責(zé)任放在哪對(duì)于對(duì)象設(shè)計(jì)是最重要的之一。重構(gòu)可以很好的解決這個(gè)問(wèn)題。以下是筆者的重構(gòu)方法注:客戶(hù):調(diào)用接口客戶(hù)類(lèi):使用了接口的類(lèi)服務(wù)類(lèi):提供服務(wù)的類(lèi) Mov...

    solocoder 評(píng)論0 收藏0
  • 讀書(shū)筆記《重構(gòu) 改善既有代碼設(shè)計(jì)

    摘要:重構(gòu)在不改變代碼的外在的行為的前提下對(duì)代碼進(jìn)行修改最大限度的減少錯(cuò)誤的幾率本質(zhì)上,就是代碼寫(xiě)好之后修改它的設(shè)計(jì)。重構(gòu)可以深入理解代碼并且?guī)椭业健M瑫r(shí)重構(gòu)可以減少引入的機(jī)率,方便日后擴(kuò)展。平行繼承目的在于消除類(lèi)之間的重復(fù)代碼。 重構(gòu) (refactoring) 在不改變代碼的外在的行為的前提下 對(duì)代碼進(jìn)行修改最大限度的減少錯(cuò)誤的幾率 本質(zhì)上, 就是代碼寫(xiě)好之后 修改它的設(shè)計(jì)。 1,書(shū)中...

    mdluo 評(píng)論0 收藏0
  • 重構(gòu)---改善既有代碼設(shè)計(jì)

    摘要:為何重構(gòu)重構(gòu)有四大好處重構(gòu)改進(jìn)軟件設(shè)計(jì)如果沒(méi)有重構(gòu),程序的設(shè)計(jì)會(huì)逐漸腐敗變質(zhì)。經(jīng)常性的重構(gòu)可以幫助維持自己該有的形態(tài)。你有一個(gè)大型函數(shù),其中對(duì)局部變量的使用使你無(wú)法采用。將這個(gè)函數(shù)放進(jìn)一個(gè)單獨(dú)對(duì)象中,如此一來(lái)局部變量就成了對(duì)象內(nèi)的字段。 哪有什么天生如此,只是我們天天堅(jiān)持。 -Zhiyuan 國(guó)慶抽出時(shí)間來(lái)閱讀這本從師傅那里借來(lái)的書(shū),聽(tīng)說(shuō)還是程序員的必讀書(shū)籍。 關(guān)于書(shū)的高清下載連...

    baihe 評(píng)論0 收藏0
  • 重構(gòu)-改善既有代碼設(shè)計(jì)(一)--重構(gòu),第一個(gè)案例

    摘要:并根據(jù)目錄選讀第章重構(gòu),第一個(gè)案例這是只是一個(gè)方法。絕大多數(shù)情況下,函數(shù)應(yīng)該放在它所使用的數(shù)據(jù)的所屬對(duì)象內(nèi)最好不要在另一個(gè)對(duì)象的屬性基礎(chǔ)上運(yùn)用語(yǔ)句。 什么是重構(gòu) 在不改變代碼外在行為的前提下,對(duì)代碼做出修改以改進(jìn)程序內(nèi)部的結(jié)構(gòu)簡(jiǎn)單地說(shuō)就是在代碼寫(xiě)好后改進(jìn)它的設(shè)計(jì) 誰(shuí)該閱讀這本書(shū) 專(zhuān)業(yè)程序員(能夠提高你的代碼質(zhì)量) 資深設(shè)計(jì)師和架構(gòu)規(guī)劃師(理解為什么需要重構(gòu),哪里需要重構(gòu)) 閱讀技巧...

    acrazing 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<