ivaneeo's blog

          自由的力量,自由的生活。

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            669 Posts :: 0 Stories :: 64 Comments :: 0 Trackbacks

          #

          客戶直接調用其server object(服務對象)的delegate class。

          在server端(某個class)建立客戶所需的所有函數,用以隱藏委托關系(delegation)。

          Hide_Delegate.png
          posted @ 2005-08-31 11:09 ivaneeo 閱讀(156) | 評論 (0)編輯 收藏

          先前(上個重構項)我從TelephoneNumber提煉出另一個class,現在我要將它inlining塞回到Person去。一開始這兩個classes是分離的:
          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;

          首先我在Person中聲明TelephoneNumber的所有[可見](public)函數:
          class Person...
              String getAreaCode() {
                 return _officeTelephone.getAreaCode();
              }
              void setAreaCode(String arg) {
                 _officeTelephone.setAreaCode(arg);
              }
              String getNumber() {
                 return
          _officeTelephone.getNumber();
              }
              void setNumber(String arg) {
                
          _officeTelephone.setNumber(arg);
              }


          現在,我要找出TelephoneNumber的所有用戶,讓它們轉而使用Person接口。于是下列代碼:
              Person martin = new Person();
              martin.getOfficeTelephone().setAreaCode("781");
          就變成了:
              Person martin = new Person();
              martin.setAreaCode("781");
          現在,我可以持續使用Move Method(142)和Move Field(146),直到TelephoneNumber不復存在。
          posted @ 2005-08-31 10:57 ivaneeo 閱讀(203) | 評論 (0)編輯 收藏

          作法(Mechanics)
            • 在absorbing class(合并端的那個class)身上聲明source class的public協議,并將其中所有函數委托(delegate)至source class。
                • ==》如果[以一個獨立接口表示source class函數]更合適的話,就應該在inlining之前先使用Extract Interface(341)。
            • 修改所有source class引用點,改而引用absorbing class。
                • ==》將source class聲明為private,以斬斷package之外的所有引用可能。
                • 同時并修改source class的名稱,這便可使編譯器幫助你捕捉到所有對于source class的“dangling references”(虛懸引用點)。
            • 編譯,測試。
            • 運用Move Method(142)和Move Field(146),將source class的特性全部搬移到absorbing class。
            • 為source class舉行一個簡單的葬禮。
          posted @ 2005-08-31 10:42 ivaneeo 閱讀(140) | 評論 (0)編輯 收藏

          動機(Motivation)
          Inline Class(154)正好與Extract Class(149)相反。如果一個class不再承擔足夠責任、不再有單獨存在的理由(這通常是因為此前的重構動作移走了這個class的責任),我就會挑選這一[萎縮class]的最頻繁用戶(也是個class),以Inline Class(154)手法將[萎縮class]塞進去。
          posted @ 2005-08-31 10:02 ivaneeo 閱讀(146) | 評論 (0)編輯 收藏

          你的某個class沒有做太多事情(沒有承擔足夠責任)。

          將class的所有特性搬移到另一個class中,然后移除原class。

          Inline_Class.png
          posted @ 2005-08-30 16:44 ivaneeo 閱讀(182) | 評論 (0)編輯 收藏

          讓我們從一個簡單的Person class開始:
          class Person...
              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;
              }

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

          在這個例子,我可以將[與電話號碼相關]的行為分離到一個獨立class中。首先我要定義一個TelephoneNumber class來表示[電話號碼]這個概念:
          class TelephoneNumber {
          }
          易如反掌!然后,我要建立從Person到TelephoneNumber的連接:
          class Person...
              private TelephoneNumber _officeTelephone = new TelephoneNumber();
          現在,我運用Move Field(146)移動一個值域:
          class TelephoneNumber {
              String getAreaCode() {
                 return _areaCode;
              }
              void setAreaCode(String arg) {
                 _areaCode = arg;
              }
              private String _areaCode;
          }

          class Person...
              public String getTelephoneNumber() {
                 return ("(" + getOfficeAreaCode() + ")" + _officeNumber);
              }
              String getOfficeAreaCode() {
                 return _officeTelephone.getAreaCode();
              }
              void setOfficeAreaCode(String arg) {
                 _officeTelephone.setAreaCode(arg);
              }

          然后我可以移動其他值域,并運用Move Method(142)將相關函數移動到TelephoneNumber class中:
          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;


          下一步要做的決定是:要不要對客戶揭示這個新class?我可以將Person中[與電話號碼相關]的函數委托(delegating)至 TelephoneNumber,從而完全隱藏這個新class;也可以直接將對用戶曝光。我還可以將它暴露給部分用戶(位于同一個package中的用 戶),而不暴露給其他用戶。

          如果我選擇暴露新class嗎,我就需要考慮別名(aliasing)帶來的危險。如果我暴露了TelephoneNumber,而有個用戶修改了對象中的_areaCode值域值,我又怎么能知道呢?而且,做出修改的可能不是直接用戶,而是用戶的用戶的用戶。


          面對這個問題,我有下列數種選擇:
          1.允許任何對象修改TelephoneNumber對象的任何部分。這就使得TelephoneNumber對象成為引用對象(reference object),對于我應該考慮使用Change Value to Reference(179)。這種情況下,Person應該是TelephoneNumber的訪問點。
          2.不許任何人[不通過Person對象就修改TelephoneNumber對象]。為了達到目的,我可以將TelephoneNumber設為不可修改的(immutable),或為它提供一個不可修改的接口(immutable interface)。
          3.另一個辦法是:先復制一個TelephoneNumber對象,然后將復制得到的新對象傳遞給用戶。但這可能會造成一定程度的迷惑,因為人們會認為他們可以修改TelephoneNumber對象值。此外,如果同一個TelephoneNumber對象被傳遞給多個用戶,也可能在用戶之間造成別名(aliasing)問題。

          Extract Class(149)是改善并發(concurrent)程序的一種常用技術,因為它使你可以提煉后的兩個classes分別加鎖(locks)。
          posted @ 2005-08-30 16:33 ivaneeo 閱讀(213) | 評論 (0)編輯 收藏

          作法(Mechanics)
            • 決定如何分解class所負責任。
            • 建立一個新class,用以表現從舊class中分離出來的責任。
                • ==》如果舊class剩下的責任與舊class名稱不符,為舊class易名。
            • 建立[從舊class訪問新class]的連接關系(link)。
                • ==》也許你有可能需要一個雙向連接。但是在真正需要它之前,不要建立[從新class同往舊class]的連接。
            • 對于你想搬移的每一個值域,運用Move Field(146)搬移之。
            • 每次搬移后,編譯、測試。
            • 使用Move Method(142)將必要函數搬移到新class。先搬移較低層函數(也就是[就其他函數調用]多于[調用其他函數]者),再搬移較高層函數。
            • 每次搬移之后,編譯、測試。
            • 檢查,精簡每個class的接口。
                • ==》如果你建立起雙向連接,檢查是否可以將它改為單向連接。
            • 決定是否讓新class暴光。如果你的的確需要暴光它,決定讓它成為reference object(引用型對象)或immutable value object(不可變之[實值型對象])。
          posted @ 2005-08-30 15:46 ivaneeo 閱讀(169) | 評論 (0)編輯 收藏

          動機(Motivation)
          如果某些數據和某些函數總是一起出現,如果某些數據經常同時變化甚至彼此相依,這就表示你應該將它們分離出去。

          另一個往往在開發后期出現的信號是class的[subtyped方式]。如果你發現subtyping只影響class的部分特性,或如果你發現某些特 性[需要以此方式subtyped],某些特性[需要以彼此方式subtyped],這就是意味你需要分解原來的class。
          posted @ 2005-08-30 15:33 ivaneeo 閱讀(174) | 評論 (0)編輯 收藏

          某個class做了應該由兩個classes做的事。

          建立一個新class,將相關的值域和函數從舊class搬移到新class。

          Extract_Class.png
          posted @ 2005-08-30 15:23 ivaneeo 閱讀(168) | 評論 (0)編輯 收藏

          如果有很多函數已經使用了_interestRate field,我應該先運用Self Encapsulate Field(171):
          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之后,我就只需要修改訪問函數就行了:

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

                 _type.setInterestRate(arg);
              }
              private double getInterestRate() {
                 return _type.getInterestRate();
              }

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

          posted @ 2005-08-30 14:59 ivaneeo 閱讀(130) | 評論 (0)編輯 收藏

          僅列出標題
          共67頁: First 上一頁 44 45 46 47 48 49 50 51 52 下一頁 Last 
          主站蜘蛛池模板: 老河口市| 房山区| 渑池县| 黑山县| 新竹县| 襄城县| 西藏| 普兰店市| 广东省| 阿瓦提县| 延吉市| 叙永县| 靖远县| 西青区| 瑞安市| 边坝县| 洱源县| SHOW| 通河县| 寿宁县| 固安县| 屯门区| 咸阳市| 平武县| 舒城县| 灵石县| 腾冲县| 南通市| 沿河| 合川市| 静乐县| 岑巩县| 栖霞市| 冕宁县| 巢湖市| 南投市| 文成县| 黎川县| 澄迈县| 壤塘县| 贞丰县|