SlideShare una empresa de Scribd logo
1 de 38
Classification 4/22/2011 1 Refactoring Improving The Design of Existing Code Ch. 7 Moving Features Between Objects Joe C Wu  Developer, WSE(Web Services Engineering) Volume
Outline Ch. 7 Moving Features Between Objects Move Method (搬移函式) Move Field (搬移欄位) Extract Class (提練類別) Inline Class (將類別內聯化) Hide Delegate (隱藏「委託關係」) Remove Middle Man (移除中間人) Introduce Foreign Method (加入外加函式) Introduce Local Extension (引入區域性擴展) Summary Classification 4/22/2011 2
Classification 4/22/2011 3 Move Method (搬移函式) 在該函式最常引用的class中建立一個有著類似行為的新函式。將舊函式變成一個單純的委託函式(delegating method),或是將舊函式完全移除。
Classification 4/22/2011 4 Move Method (搬移函式) 動機 當一個Class有太多的行為. 當一個Class與另個Class有太多合作而型成高度耦合(highly coupled). 使系統中的classes更簡單。 作法 這個函式與哪個物件的交流比較多? 檢查source class定義的method所使用的一切features. 檢查sub class, super class. 搬移source method to target method -> Compile target class. 決定如何從source 正確引用target object. 修改source method 成為delegating method. -> Compile and Test 刪除source method 或將它當作一個delegating method保留下來。 將source class中對source method的引用替換為target method. Compile and Test. 很難決定 -> 或許移動這個函式與否,並不那麼重要。
Move Method (搬移函式) 範例 Classification 4/22/2011 5 Class Account…    double overdraftCharge()  {       if ( _type.isPremium()) {          double result = 10;          if (_dayOverdrawn > 7) result += (_daysOverdrawn – 7) * 0.85;          return result;       }// end if       else return _daysOverdrawn * 1.75; } // end overdraftChrge double bankCharge () {    double result = 4.5;    if (_daysOverdrawn > 0) result += overdraftCharge();    return result; } // end bankCharge private AccountType _type; private int _daysOverdrawn; Suppose you wish to have other account types  and decide to build an account type class to contain the methods
Move Method (搬移函式) Classification 4/22/2011 6 Class AccountType…			several account types – diff method     double overdraftCharge(intdaysOverdrawn)  {        if (isPremium()) {          double result = 10;          if (dayOverdrawn > 7) result += (daysOverdrawn – 7) * 0.85;          return result;       }// end if       else return _daysOverdrawn * 1.75; } // end overdraftChrge Class Account…     double bankCharge () {    double result = 4.5;    if (_days|Overdrawn |> 0) result += _type.overdraftCharge(_daysOverdrawn);    return result; } // end bankCharge
Classification 4/22/2011 7 Move Field (搬移欄位) 某個class的field,被別的class使用更多次。 在target class建立一個new field,修改source field的所有用戶,令它們改用new field.
Classification 4/22/2011 8 Move Field (搬移欄位) 動機 某個class的field,被別的class使用更多次。 透過Get/Set間接進行。 也移動使用這個field的使用者。(取決於介面是否保持一致) 使用Extract Class時,也可能需要搬移field,這時會先搬field. 作法 Encapsulate Field  (Get/Set) Compile and Test. 在target class建立同樣的field,並建立Getting/Setting。 Compile target class. 取得target object (若現有field or method不能做到,建一個field來存。 將所有source field的引用,改為存取target field。 Compile and Test.
Classification 4/22/2011 9 Move Field (搬移欄位) 範例 Class Account…    private AccoutnType _type;    private double _interestRate;    double interestForAmount)days (double amount, int days)   {       return )interestRate * amount * days /365;    } // end interestForAmount Would like to move interestRate to the AccountType class because it is used more in that class.
Classification 4/22/2011 10 Move Field (搬移欄位) 範例 Class AccountType….    private double _interestRate; void setInterestRate (double arg) { _interestRate = arg; }    double getInterestRate () { return _interestRate; } ………. double interestForAccount_days (double amount, int days) {    return _type.getInterestRate() * amount * days/365; } // end interestForAccount_days Move _interestRate. In the original class reference get and set methods for the field.
Classification 4/22/2011 11 Extract Class (提練類別) 某個class做了應該由兩個classes做的事。 建立一個新的class,將相關的欄位和函式從舊class移至新class.
Classification 4/22/2011 12 Extract Class (提練類別) 動機 一個class應該是一個清楚的抽象性(abstract),處理一些明確的責任。 Class太大會不易理解。 某些資料和函式總是一起出現、某些資料常同時變化並彼此相依,表示他們該被分離出去。 作法 決定如何分解class所負責任。 建立新的class,將舊class的責任交給它。 建立舊class與新class之間的link。 Move Field -> Test Move Method -> Test 檢查、精簡每個class的介面。 決定是否讓新class曝光 => reference object / immutable value object
Classification 4/22/2011 13 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; } Extract Class (提練類別) 範例
Classification 4/22/2011 14 Extract Class (提練類別) Move Field class Person {     private TelephoneNumber_officeTelephone= new TelephoneNumber();     public String getTelephoneNumber() {         return ("(" + getOfficeAreaCode() + ") " + _officeNumber); }     String getOfficeAreaCode() {         return _officeTelephone.getAreaCode(); }     void setOfficeAreaCode(String arg) {         _officeTelephone.setAreaCode(arg); } } class TelephoneNumber {     String getAreaCode() {         return _areaCode; }     void setAreaCode(String arg) {         _areaCode = arg; }     private String _areaCode; }
Extract Class (提練類別) Move Method Classification 4/22/2011 15 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 {     public String getName() {         return _name; }     public String getTelephoneNumber() {         return _officeTelephone.getTelephoneNumber(); } TelephoneNumbergetOfficeTelephone() {         return _officeTelephone; }     private String _name;     private TelephoneNumber _officeTelephone = new TelephoneNumber(); }
Extract Class (提練類別) TelephoneNumber Public? Private? Protected? 若public新的class,要考慮別名(aliasing)的問題 允許任何物件修改TelephoneNumber物件的任何部份 使它成為Reference Object。(person為的存取點)  (Ch.8) 不許任何人”不透過Person就修改它” 設為immutable或是提供immutable interface。 先複製一個TelephoneNumber物件,將這個物件傳給用戶,當然這也會造成一定程度的迷惑。 你可以為提煉後的class加鎖(lock)。但要小心鎖定的問題。 Classification 4/22/2011 16
Classification 4/22/2011 17 Inline Class (將類別內聯化) 你的某個class沒有做太多事情(沒有承擔足夠的責任) 將class的所有特性搬移到另一個class中,然後移除原class.
Classification 4/22/2011 18 Inline Class (將類別內聯化) 動機 如果一個class不再承擔足夠的責任,不再有單獨存在的理由。 挑選最頻繁使用這個「萎縮class」的用戶,以Inline Class手法塞進去。 作法 在absorbing class(合併端class)宣告source class的public協定,並將所有函式委託(delegate)至source class. 修改source class的引用點->absorbing class。 Compile and Test Move Method and Move Field,將source class的特性移過去。 幫source class舉行一個簡單的喪禮。
Classification 4/22/2011 19 Inline Class (將類別內聯化) 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 {     public String getName() {return _name;}     public String getTelephoneNumber() {return _officeTelephone.getTelephoneNumber();} TelephoneNumbergetOfficeTelephone() {return _officeTelephone;}     private String _name;     private TelephoneNumber _officeTelephone = new TelephoneNumber();  String getAreaCode() { return _officeTelephone.getAreaCode();}     void setAreaCode(String arg) {  _officeTelephone.setAreaCode(arg);}     String getNumber() { return _officeTelephone.getNumber();}     void setNumber(String arg) { _officeTelephone.setNumber(arg);} }
Classification 4/22/2011 20 Inline Class (將類別內聯化) Person martin = new Person(); martin.getOfficeTelephone().setAreaCode ("781"); Person martin = new Person(); martin.setAreaCode ("781");
Classification 4/22/2011 21 Hide Delegate (隱藏「委託關係」) 客戶直接呼叫其server object(服務物件)的delegate class。 在Server端建立客戶所需的所有函式,用以隱藏委托關係(delegation)。
Classification 4/22/2011 22 Hide Delegate (隱藏「委託關係」) 動機 封裝即使不是物件的最關鍵特徵,也是最關鍵特徵之一。 如果某個客戶呼叫了「建立於server object的某個欄位基礎之上」的函式,客戶就必需知道這個委託物件(delegate object),萬一委託關係發生變化,客戶也得相應變化。 將委託關係隱藏起來,去除這種依存性,將變化限制在server中,不會波及客戶。
Classification 4/22/2011 23 Hide Delegate (隱藏「委託關係」) 作法 對每一個委託關係中的函式,在server端建立一個簡單的委託函式(delegating method)。 調整客戶,令它只呼叫server提供的函式 Compile and Test 如果將來不再有任何客戶需要用到Delegate,便可移除server中的存取函式 Compile and Test
Classification 4/22/2011 24 Hide Delegate (隱藏「委託關係」) class Person {     Department _department;     public Department getDepartment() {         return _department; }     public void setDepartment(Department arg) {         _department = arg; } } 範例 manager = john.getDepartment().getManager();  public Person getManager() {         return _department.getManager(); } class Department {     private String _chargeCode;     private Person _manager;     public Department(Person manager) {         _manager = manager; }     public Person getManager() {         return _manager; } } manager = john.getManager();
Classification 4/22/2011 25 Remove Middle Man (移除中間人) 某個class做了過多的簡單委託動作(simple delegation)。 讓客戶直接呼叫delegate(受託類別)。
Classification 4/22/2011 26 Remove Middle Man (移除中間人) 動機 Hide Delegate的代價 當客戶要用到delegate的新特性時,你就必須在server端添加一個簡單委託函式。delegate的特性(功能)愈來愈多,就愈來愈痛苦。 很難說什麼程度的隱藏才是合適的。 隨著系統的變化,改成合適的就好了。 重構的意義就在於:你永遠不必說什麼對不起,只要把出問題的地方修補好就行了。 作法 建立一個函式,用以取代delegate(受托物件)。 對於每個委託函式(delegate method),在server中刪除該函式,並將「客戶對該函式的呼叫」替換為「對delegate的呼叫」。 Compile and Test
Classification 4/22/2011 27 Remove Middle Man (移除中間人) 範例 class Person {     Department _department;     public Person getManager() {         return _department.getManager(); } } class Department {     private Person _manager;     public Department(Person manager) {         _manager = manager; } } manager = john.getManager(); class Person {     public Department getDepartment() {         return _department; } } manager = john.getDepartment().getManager();
Classification 4/22/2011 28 Introduce Foreign Method (加入外加函式) 你所使用的server class需要一個函式,但你無法修改這個class。 在client class中建立一個函式,並以一個server class實體作為第一引數(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); }
Classification 4/22/2011 29 Introduce Foreign Method (加入外加函式) 動機 你正在使用一個class,它真的很好,為你提供了你想要的所有服務。 當你需要一個新服務,這個class卻無法供應… 如果可以修改源碼,你便可以加一個新函式,如果不能,你就得在客戶端編碼,補足你要的函式。 如果你需要使用很多次,你就得不斷重初這些程式碼… 如果你以外加函式實現一個新功能,那就是一個明確信號: 這個函式原本應該在提供服務的class中加以實現。 如果一個server class加入了大量的外加函式,你就不應該再使用本項重構,而應該使用Introduce Local Extension。
Classification 4/22/2011 30 Introduce Foreign Method (加入外加函式) 作法 在client class中建立一個函式,用來提供你需要的功能。 這個函式不應該取用client class的任何特性,如果需要,用參數傳給它。 以server  class實體作為該函式的第一個參數。 將該函式注釋為「外加函式(foreign method),應在server class實現。 範例 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); }
Classification 4/22/2011 31 Introduce Local Extension (引入區域性擴展) 你所使用的server class需要一些額外函式,但你無法修改這個class。 建立一個新class,使用包含這些額外函式。讓這個擴展品成盥source class的sub class(子類別)或wrapper(外覆類別)。
Classification 4/22/2011 32 Introduce Local Extension (引入區域性擴展) 動機 如果只需要一兩個函式,可以使用Introduce Foreign Method。 超果兩個,可以用這個方法將這些函式組織在一起,這種方式稱之為local extension(區域性擴展) 是一個獨立的class,卻也是其extended class的subtype。 堅持「函式和資料應該被包裝在形式良好的單元內」。 如果你一直把本該在extension class的程式零散放在其他classes中,只會讓其他這些classes變得過分複雜,並使得其中函式難以被復用。 local extension有兩種作法 Subclass 必須在物件創建期實施。 必須新增一個class,但是當原物件也被使用時,就要考慮維護兩份資料的問題。 Wrapper 通常首選subclass,因為工作量比較少。
Classification 4/22/2011 33 Introduce Local Extension (引入區域性擴展) 作法 建立一個extension class,將它作為原物(原類別)的subclass或wrapper。 在extension class中加入轉型建構式(converting constructors)。 Converting constructors: 接受原物作為參數 在extension class中加入新特性。 根據需要,將原物(original)替換為擴展物(extension)。 將「針對原始類別而定義的所有外加函式(foreign ethods)」搬移到extension class中。
Classification 4/22/2011 34 Introduce Local Extension (引入區域性擴展) 範例(Subclass) class MfDateSub extends Date {     public MfDateSub (String dateString) {         super (dateString); }     public MfDateSub (Date arg) {         super (arg.getTime()); }     Date nextDay() {         return new Date (getYear(),getMonth(), getDate() + 1); } } 轉型建構式(converting constructors)
Classification 4/22/2011 35 Introduce Local Extension (引入區域性擴展) class MfDateWrap {     private Date _original;     public MfDateWrap(String dateString) {         _original = new Date(dateString); }     public MfDateWrap(Date arg) { _original = arg; } // 為原始類別的所有函式提供委託函式…     public intgetYear()     {return _original.getYear();}     public intgetMonth()     {return _original.getMonth();}     public intgetDate()     {return _original.getDate();}     public boolean equals(MfDateWraparg)     {return (toDate().equals(arg.toDate()));}     Date nextDay() {         return new Date(getYear(), getMonth(), getDate() + 1); } } 範例(Wrapper) 如何處理「接受原始類別之實體為參數」的函式? 只是執行一個單純的委託動作(delegate) public boolean after (Date arg) aWrapper.after(aDate) aWrapper.after(anotherWrapper) aDate.after(aWrapper)
Introduce Local Extension (引入區域性擴展) 範例(Wrapper) 上一頁”after” method這種overriding的目的是為了向用戶隱藏wrapper的存在,這是一個好策略。 不過在某些系統所提供的函式(如equals)會出問題。 public booleanequals (Date arg) // causes problems 這樣做是危險的,因為Java系統的其他部份都認為equals符合交換律:如果a.equals(b)為真,b.equals(a)也必為真。 違反這樣的規則將使我遭遇一大堆莫名其妙的錯誤,但是又無法同時修改Date,所以建議向用戶曝露「我進行了包裝」 public booleanequalsDate(Date arg) public booleanequalsDate(MfDateWraparg) Subclass則不會有這問題,只要不覆寫original class中的函式。 一般來說不會在extension class中覆寫original class的函式,只會添加新函式。 Classification 4/22/2011 36
Classification 4/22/2011 37 Summary 決定把責任放在哪兒? 重構的基本手法 Move Field > Move Method Class責任 過多 或是 過少 Extract Class V.S Inline Class Class使用另一Class Hide Delegate將關係隱藏起來 因為Hide delegate導致擁有者的介面經常變化 Remove Middle Man 當我不能存取某個class的源碼,又想把其他責任移進去 Introduce Foreign Method (只加一、二個函式) Introduce Local Extension
Classification 4/22/2011 38

Más contenido relacionado

La actualidad más candente

Coding guideline
Coding guidelineCoding guideline
Coding guideline
斯理 衛
 
改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法
crasysatan
 
Oracle公司内部数据库培训资料
Oracle公司内部数据库培训资料Oracle公司内部数据库培训资料
Oracle公司内部数据库培训资料
yiditushe
 
第9章 transact sql程序设计
第9章   transact sql程序设计第9章   transact sql程序设计
第9章 transact sql程序设计
hanmo1988
 
Java8 lambda
Java8 lambdaJava8 lambda
Java8 lambda
koji lin
 

La actualidad más candente (20)

系統程式
系統程式系統程式
系統程式
 
Swift编程语言入门教程 中文版
Swift编程语言入门教程 中文版Swift编程语言入门教程 中文版
Swift编程语言入门教程 中文版
 
Python分支作業
Python分支作業Python分支作業
Python分支作業
 
第4章函数
第4章函数第4章函数
第4章函数
 
TA-java-method-109
TA-java-method-109TA-java-method-109
TA-java-method-109
 
Coding guideline
Coding guidelineCoding guideline
Coding guideline
 
TA Lesson3 - Method
TA Lesson3 - MethodTA Lesson3 - Method
TA Lesson3 - Method
 
改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法
 
Sql培训 (1)
Sql培训 (1)Sql培训 (1)
Sql培训 (1)
 
Python learn guide
Python learn guidePython learn guide
Python learn guide
 
Arrays的Sort算法分析
Arrays的Sort算法分析Arrays的Sort算法分析
Arrays的Sort算法分析
 
建置Python開發環境
建置Python開發環境建置Python開發環境
建置Python開發環境
 
Oracle公司内部数据库培训资料
Oracle公司内部数据库培训资料Oracle公司内部数据库培训资料
Oracle公司内部数据库培训资料
 
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
 
第9章 transact sql程序设计
第9章   transact sql程序设计第9章   transact sql程序设计
第9章 transact sql程序设计
 
Python元組,字典,集合
Python元組,字典,集合Python元組,字典,集合
Python元組,字典,集合
 
期中考課輔
期中考課輔期中考課輔
期中考課輔
 
Java8 lambda
Java8 lambdaJava8 lambda
Java8 lambda
 
前端测试
前端测试前端测试
前端测试
 
Ecmascript
EcmascriptEcmascript
Ecmascript
 

Destacado

Approaching real-time-hadoop
Approaching real-time-hadoopApproaching real-time-hadoop
Approaching real-time-hadoop
Chris Huang
 
重構—改善既有程式的設計(chapter 9)
重構—改善既有程式的設計(chapter 9)重構—改善既有程式的設計(chapter 9)
重構—改善既有程式的設計(chapter 9)
Chris Huang
 
重構—改善既有程式的設計(chapter 12,13)
重構—改善既有程式的設計(chapter 12,13)重構—改善既有程式的設計(chapter 12,13)
重構—改善既有程式的設計(chapter 12,13)
Chris Huang
 
重構—改善既有程式的設計(chapter 6)
重構—改善既有程式的設計(chapter 6)重構—改善既有程式的設計(chapter 6)
重構—改善既有程式的設計(chapter 6)
Chris Huang
 
重構—改善既有程式的設計(chapter 8)part 1
重構—改善既有程式的設計(chapter 8)part 1重構—改善既有程式的設計(chapter 8)part 1
重構—改善既有程式的設計(chapter 8)part 1
Chris Huang
 
重構—改善既有程式的設計(chapter 2,3)
重構—改善既有程式的設計(chapter 2,3)重構—改善既有程式的設計(chapter 2,3)
重構—改善既有程式的設計(chapter 2,3)
Chris Huang
 
重構—改善既有程式的設計(chapter 4,5)
重構—改善既有程式的設計(chapter 4,5)重構—改善既有程式的設計(chapter 4,5)
重構—改善既有程式的設計(chapter 4,5)
Chris Huang
 
重構—改善既有程式的設計(chapter 8)part 2
重構—改善既有程式的設計(chapter 8)part 2重構—改善既有程式的設計(chapter 8)part 2
重構—改善既有程式的設計(chapter 8)part 2
Chris Huang
 
Real time big data applications with hadoop ecosystem
Real time big data applications with hadoop ecosystemReal time big data applications with hadoop ecosystem
Real time big data applications with hadoop ecosystem
Chris Huang
 
重構—改善既有程式的設計(chapter 1)
重構—改善既有程式的設計(chapter 1)重構—改善既有程式的設計(chapter 1)
重構—改善既有程式的設計(chapter 1)
Chris Huang
 

Destacado (11)

Approaching real-time-hadoop
Approaching real-time-hadoopApproaching real-time-hadoop
Approaching real-time-hadoop
 
重構—改善既有程式的設計(chapter 9)
重構—改善既有程式的設計(chapter 9)重構—改善既有程式的設計(chapter 9)
重構—改善既有程式的設計(chapter 9)
 
重構—改善既有程式的設計(chapter 12,13)
重構—改善既有程式的設計(chapter 12,13)重構—改善既有程式的設計(chapter 12,13)
重構—改善既有程式的設計(chapter 12,13)
 
重構—改善既有程式的設計(chapter 6)
重構—改善既有程式的設計(chapter 6)重構—改善既有程式的設計(chapter 6)
重構—改善既有程式的設計(chapter 6)
 
重構—改善既有程式的設計(chapter 8)part 1
重構—改善既有程式的設計(chapter 8)part 1重構—改善既有程式的設計(chapter 8)part 1
重構—改善既有程式的設計(chapter 8)part 1
 
重構—改善既有程式的設計(chapter 2,3)
重構—改善既有程式的設計(chapter 2,3)重構—改善既有程式的設計(chapter 2,3)
重構—改善既有程式的設計(chapter 2,3)
 
重構—改善既有程式的設計(chapter 4,5)
重構—改善既有程式的設計(chapter 4,5)重構—改善既有程式的設計(chapter 4,5)
重構—改善既有程式的設計(chapter 4,5)
 
重構—改善既有程式的設計(chapter 8)part 2
重構—改善既有程式的設計(chapter 8)part 2重構—改善既有程式的設計(chapter 8)part 2
重構—改善既有程式的設計(chapter 8)part 2
 
Real time big data applications with hadoop ecosystem
Real time big data applications with hadoop ecosystemReal time big data applications with hadoop ecosystem
Real time big data applications with hadoop ecosystem
 
重構—改善既有程式的設計(chapter 1)
重構—改善既有程式的設計(chapter 1)重構—改善既有程式的設計(chapter 1)
重構—改善既有程式的設計(chapter 1)
 
A Graph Service for Global Web Entities Traversal and Reputation Evaluation B...
A Graph Service for Global Web Entities Traversal and Reputation Evaluation B...A Graph Service for Global Web Entities Traversal and Reputation Evaluation B...
A Graph Service for Global Web Entities Traversal and Reputation Evaluation B...
 

Similar a 重構—改善既有程式的設計(chapter 7)

《Java程序设计》期末考试试题 (六)
《Java程序设计》期末考试试题 (六)《Java程序设计》期末考试试题 (六)
《Java程序设计》期末考试试题 (六)
jane2006
 
Java Collections中的Fail Fast机制
Java Collections中的Fail Fast机制Java Collections中的Fail Fast机制
Java Collections中的Fail Fast机制
yiditushe
 
Ejb工作原理学习笔记
Ejb工作原理学习笔记Ejb工作原理学习笔记
Ejb工作原理学习笔记
yiditushe
 
Js的国(转载)
Js的国(转载)Js的国(转载)
Js的国(转载)
Leo Hui
 
Java script closures
Java script closuresJava script closures
Java script closures
skywalker1114
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验
QLeelulu
 
jQuery源码学习
jQuery源码学习jQuery源码学习
jQuery源码学习
fangdeng
 

Similar a 重構—改善既有程式的設計(chapter 7) (20)

Ian 20151002 es2015
Ian 20151002 es2015Ian 20151002 es2015
Ian 20151002 es2015
 
《Java程序设计》期末考试试题 (六)
《Java程序设计》期末考试试题 (六)《Java程序设计》期末考试试题 (六)
《Java程序设计》期末考试试题 (六)
 
Java Collections中的Fail Fast机制
Java Collections中的Fail Fast机制Java Collections中的Fail Fast机制
Java Collections中的Fail Fast机制
 
Java物件導向
Java物件導向Java物件導向
Java物件導向
 
小谈Javascript设计模式
小谈Javascript设计模式小谈Javascript设计模式
小谈Javascript设计模式
 
Sun java
Sun javaSun java
Sun java
 
Ejb工作原理学习笔记
Ejb工作原理学习笔记Ejb工作原理学习笔记
Ejb工作原理学习笔记
 
Js的国(转载)
Js的国(转载)Js的国(转载)
Js的国(转载)
 
Java script closures
Java script closuresJava script closures
Java script closures
 
Java script closures
Java script closuresJava script closures
Java script closures
 
Php for fe
Php for fePhp for fe
Php for fe
 
About closure
About closureAbout closure
About closure
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验
 
PHPUnit + Xdebug 单元测试技术
PHPUnit + Xdebug 单元测试技术PHPUnit + Xdebug 单元测试技术
PHPUnit + Xdebug 单元测试技术
 
twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹
 
Scala
ScalaScala
Scala
 
淺談C#物件導向與DesignPattern.pdf
淺談C#物件導向與DesignPattern.pdf淺談C#物件導向與DesignPattern.pdf
淺談C#物件導向與DesignPattern.pdf
 
jQuery源码学习
jQuery源码学习jQuery源码学习
jQuery源码学习
 
Scala
ScalaScala
Scala
 
C語言結構與串列
C語言結構與串列 C語言結構與串列
C語言結構與串列
 

Más de Chris Huang

20130310 solr tuorial
20130310 solr tuorial20130310 solr tuorial
20130310 solr tuorial
Chris Huang
 
Scaling big-data-mining-infra2
Scaling big-data-mining-infra2Scaling big-data-mining-infra2
Scaling big-data-mining-infra2
Chris Huang
 
Hbase status quo apache-con europe - nov 2012
Hbase status quo   apache-con europe - nov 2012Hbase status quo   apache-con europe - nov 2012
Hbase status quo apache-con europe - nov 2012
Chris Huang
 
Hbase schema design and sizing apache-con europe - nov 2012
Hbase schema design and sizing   apache-con europe - nov 2012Hbase schema design and sizing   apache-con europe - nov 2012
Hbase schema design and sizing apache-con europe - nov 2012
Chris Huang
 
重構—改善既有程式的設計(chapter 10)
重構—改善既有程式的設計(chapter 10)重構—改善既有程式的設計(chapter 10)
重構—改善既有程式的設計(chapter 10)
Chris Huang
 
Designs, Lessons and Advice from Building Large Distributed Systems
Designs, Lessons and Advice from Building Large Distributed SystemsDesigns, Lessons and Advice from Building Large Distributed Systems
Designs, Lessons and Advice from Building Large Distributed Systems
Chris Huang
 
Hw5 my house in yong he
Hw5 my house in yong heHw5 my house in yong he
Hw5 my house in yong he
Chris Huang
 
Social English Class HW3
Social English Class HW3Social English Class HW3
Social English Class HW3
Chris Huang
 
火柴人的故事
火柴人的故事火柴人的故事
火柴人的故事
Chris Huang
 
中德文化比較
中德文化比較中德文化比較
中德文化比較
Chris Huang
 
Sm Case4 Fuji Xerox
Sm Case4 Fuji XeroxSm Case4 Fuji Xerox
Sm Case4 Fuji Xerox
Chris Huang
 
Disney報告 最終版
Disney報告 最終版Disney報告 最終版
Disney報告 最終版
Chris Huang
 

Más de Chris Huang (19)

Data compression, data security, and machine learning
Data compression, data security, and machine learningData compression, data security, and machine learning
Data compression, data security, and machine learning
 
Kks sre book_ch10
Kks sre book_ch10Kks sre book_ch10
Kks sre book_ch10
 
Kks sre book_ch1,2
Kks sre book_ch1,2Kks sre book_ch1,2
Kks sre book_ch1,2
 
20130310 solr tuorial
20130310 solr tuorial20130310 solr tuorial
20130310 solr tuorial
 
Scaling big-data-mining-infra2
Scaling big-data-mining-infra2Scaling big-data-mining-infra2
Scaling big-data-mining-infra2
 
Applying Media Content Analysis to the Production of Musical Videos as Summar...
Applying Media Content Analysis to the Production of Musical Videos as Summar...Applying Media Content Analysis to the Production of Musical Videos as Summar...
Applying Media Content Analysis to the Production of Musical Videos as Summar...
 
Wissbi osdc pdf
Wissbi osdc pdfWissbi osdc pdf
Wissbi osdc pdf
 
Hbase status quo apache-con europe - nov 2012
Hbase status quo   apache-con europe - nov 2012Hbase status quo   apache-con europe - nov 2012
Hbase status quo apache-con europe - nov 2012
 
Hbase schema design and sizing apache-con europe - nov 2012
Hbase schema design and sizing   apache-con europe - nov 2012Hbase schema design and sizing   apache-con europe - nov 2012
Hbase schema design and sizing apache-con europe - nov 2012
 
重構—改善既有程式的設計(chapter 10)
重構—改善既有程式的設計(chapter 10)重構—改善既有程式的設計(chapter 10)
重構—改善既有程式的設計(chapter 10)
 
Designs, Lessons and Advice from Building Large Distributed Systems
Designs, Lessons and Advice from Building Large Distributed SystemsDesigns, Lessons and Advice from Building Large Distributed Systems
Designs, Lessons and Advice from Building Large Distributed Systems
 
Hw5 my house in yong he
Hw5 my house in yong heHw5 my house in yong he
Hw5 my house in yong he
 
Social English Class HW4
Social English Class HW4Social English Class HW4
Social English Class HW4
 
Social English Class HW3
Social English Class HW3Social English Class HW3
Social English Class HW3
 
Sm Case1 Ikea
Sm Case1 IkeaSm Case1 Ikea
Sm Case1 Ikea
 
火柴人的故事
火柴人的故事火柴人的故事
火柴人的故事
 
中德文化比較
中德文化比較中德文化比較
中德文化比較
 
Sm Case4 Fuji Xerox
Sm Case4 Fuji XeroxSm Case4 Fuji Xerox
Sm Case4 Fuji Xerox
 
Disney報告 最終版
Disney報告 最終版Disney報告 最終版
Disney報告 最終版
 

Último

10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习
10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习
10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习
PUAXINYEEMoe
 
法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个
法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个
法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个
michaelell902
 

Último (6)

1.🎉“黑客”如何修改成绩?🤔🎉 在这个信息爆炸的时代,我们经常会看到各种作弊手段。但是你知道吗?有一种作弊方式可能比你想象中更巧妙:它就是——黑客![单...
1.🎉“黑客”如何修改成绩?🤔🎉 在这个信息爆炸的时代,我们经常会看到各种作弊手段。但是你知道吗?有一种作弊方式可能比你想象中更巧妙:它就是——黑客![单...1.🎉“黑客”如何修改成绩?🤔🎉 在这个信息爆炸的时代,我们经常会看到各种作弊手段。但是你知道吗?有一种作弊方式可能比你想象中更巧妙:它就是——黑客![单...
1.🎉“黑客”如何修改成绩?🤔🎉 在这个信息爆炸的时代,我们经常会看到各种作弊手段。但是你知道吗?有一种作弊方式可能比你想象中更巧妙:它就是——黑客![单...
 
10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习
10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习
10.2.1 马来西亚各州名称的由来六年级历史单元练习马来西亚各州名称的由来练习
 
taibif_開放資料流程-清理資料01-通則_20240509_20240509.pdf
taibif_開放資料流程-清理資料01-通則_20240509_20240509.pdftaibif_開放資料流程-清理資料01-通則_20240509_20240509.pdf
taibif_開放資料流程-清理資料01-通則_20240509_20240509.pdf
 
taibif_資料標準概念介紹_20240509_20240509_20340509.pdf
taibif_資料標準概念介紹_20240509_20240509_20340509.pdftaibif_資料標準概念介紹_20240509_20240509_20340509.pdf
taibif_資料標準概念介紹_20240509_20240509_20340509.pdf
 
啟思中國語文 - 中二 單元一 - 孟嘗君列傳 - 記敍的方法和人稱1.pptx
啟思中國語文 - 中二 單元一 - 孟嘗君列傳 - 記敍的方法和人稱1.pptx啟思中國語文 - 中二 單元一 - 孟嘗君列傳 - 記敍的方法和人稱1.pptx
啟思中國語文 - 中二 單元一 - 孟嘗君列傳 - 記敍的方法和人稱1.pptx
 
法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个
法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个
法国蒙彼利埃国家高等建筑学院毕业证制作/德语歌德B1证书/加拿大新斯科舍省农业学院文凭加急制作一个
 

重構—改善既有程式的設計(chapter 7)

  • 1. Classification 4/22/2011 1 Refactoring Improving The Design of Existing Code Ch. 7 Moving Features Between Objects Joe C Wu Developer, WSE(Web Services Engineering) Volume
  • 2. Outline Ch. 7 Moving Features Between Objects Move Method (搬移函式) Move Field (搬移欄位) Extract Class (提練類別) Inline Class (將類別內聯化) Hide Delegate (隱藏「委託關係」) Remove Middle Man (移除中間人) Introduce Foreign Method (加入外加函式) Introduce Local Extension (引入區域性擴展) Summary Classification 4/22/2011 2
  • 3. Classification 4/22/2011 3 Move Method (搬移函式) 在該函式最常引用的class中建立一個有著類似行為的新函式。將舊函式變成一個單純的委託函式(delegating method),或是將舊函式完全移除。
  • 4. Classification 4/22/2011 4 Move Method (搬移函式) 動機 當一個Class有太多的行為. 當一個Class與另個Class有太多合作而型成高度耦合(highly coupled). 使系統中的classes更簡單。 作法 這個函式與哪個物件的交流比較多? 檢查source class定義的method所使用的一切features. 檢查sub class, super class. 搬移source method to target method -> Compile target class. 決定如何從source 正確引用target object. 修改source method 成為delegating method. -> Compile and Test 刪除source method 或將它當作一個delegating method保留下來。 將source class中對source method的引用替換為target method. Compile and Test. 很難決定 -> 或許移動這個函式與否,並不那麼重要。
  • 5. Move Method (搬移函式) 範例 Classification 4/22/2011 5 Class Account… double overdraftCharge() { if ( _type.isPremium()) { double result = 10; if (_dayOverdrawn > 7) result += (_daysOverdrawn – 7) * 0.85; return result; }// end if else return _daysOverdrawn * 1.75; } // end overdraftChrge double bankCharge () { double result = 4.5; if (_daysOverdrawn > 0) result += overdraftCharge(); return result; } // end bankCharge private AccountType _type; private int _daysOverdrawn; Suppose you wish to have other account types and decide to build an account type class to contain the methods
  • 6. Move Method (搬移函式) Classification 4/22/2011 6 Class AccountType… several account types – diff method double overdraftCharge(intdaysOverdrawn) { if (isPremium()) { double result = 10; if (dayOverdrawn > 7) result += (daysOverdrawn – 7) * 0.85; return result; }// end if else return _daysOverdrawn * 1.75; } // end overdraftChrge Class Account… double bankCharge () { double result = 4.5; if (_days|Overdrawn |> 0) result += _type.overdraftCharge(_daysOverdrawn); return result; } // end bankCharge
  • 7. Classification 4/22/2011 7 Move Field (搬移欄位) 某個class的field,被別的class使用更多次。 在target class建立一個new field,修改source field的所有用戶,令它們改用new field.
  • 8. Classification 4/22/2011 8 Move Field (搬移欄位) 動機 某個class的field,被別的class使用更多次。 透過Get/Set間接進行。 也移動使用這個field的使用者。(取決於介面是否保持一致) 使用Extract Class時,也可能需要搬移field,這時會先搬field. 作法 Encapsulate Field (Get/Set) Compile and Test. 在target class建立同樣的field,並建立Getting/Setting。 Compile target class. 取得target object (若現有field or method不能做到,建一個field來存。 將所有source field的引用,改為存取target field。 Compile and Test.
  • 9. Classification 4/22/2011 9 Move Field (搬移欄位) 範例 Class Account… private AccoutnType _type; private double _interestRate; double interestForAmount)days (double amount, int days) { return )interestRate * amount * days /365; } // end interestForAmount Would like to move interestRate to the AccountType class because it is used more in that class.
  • 10. Classification 4/22/2011 10 Move Field (搬移欄位) 範例 Class AccountType…. private double _interestRate; void setInterestRate (double arg) { _interestRate = arg; } double getInterestRate () { return _interestRate; } ………. double interestForAccount_days (double amount, int days) { return _type.getInterestRate() * amount * days/365; } // end interestForAccount_days Move _interestRate. In the original class reference get and set methods for the field.
  • 11. Classification 4/22/2011 11 Extract Class (提練類別) 某個class做了應該由兩個classes做的事。 建立一個新的class,將相關的欄位和函式從舊class移至新class.
  • 12. Classification 4/22/2011 12 Extract Class (提練類別) 動機 一個class應該是一個清楚的抽象性(abstract),處理一些明確的責任。 Class太大會不易理解。 某些資料和函式總是一起出現、某些資料常同時變化並彼此相依,表示他們該被分離出去。 作法 決定如何分解class所負責任。 建立新的class,將舊class的責任交給它。 建立舊class與新class之間的link。 Move Field -> Test Move Method -> Test 檢查、精簡每個class的介面。 決定是否讓新class曝光 => reference object / immutable value object
  • 13. Classification 4/22/2011 13 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; } Extract Class (提練類別) 範例
  • 14. Classification 4/22/2011 14 Extract Class (提練類別) Move Field class Person { private TelephoneNumber_officeTelephone= new TelephoneNumber(); public String getTelephoneNumber() { return ("(" + getOfficeAreaCode() + ") " + _officeNumber); } String getOfficeAreaCode() { return _officeTelephone.getAreaCode(); } void setOfficeAreaCode(String arg) { _officeTelephone.setAreaCode(arg); } } class TelephoneNumber { String getAreaCode() { return _areaCode; } void setAreaCode(String arg) { _areaCode = arg; } private String _areaCode; }
  • 15. Extract Class (提練類別) Move Method Classification 4/22/2011 15 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 { public String getName() { return _name; } public String getTelephoneNumber() { return _officeTelephone.getTelephoneNumber(); } TelephoneNumbergetOfficeTelephone() { return _officeTelephone; } private String _name; private TelephoneNumber _officeTelephone = new TelephoneNumber(); }
  • 16. Extract Class (提練類別) TelephoneNumber Public? Private? Protected? 若public新的class,要考慮別名(aliasing)的問題 允許任何物件修改TelephoneNumber物件的任何部份 使它成為Reference Object。(person為的存取點) (Ch.8) 不許任何人”不透過Person就修改它” 設為immutable或是提供immutable interface。 先複製一個TelephoneNumber物件,將這個物件傳給用戶,當然這也會造成一定程度的迷惑。 你可以為提煉後的class加鎖(lock)。但要小心鎖定的問題。 Classification 4/22/2011 16
  • 17. Classification 4/22/2011 17 Inline Class (將類別內聯化) 你的某個class沒有做太多事情(沒有承擔足夠的責任) 將class的所有特性搬移到另一個class中,然後移除原class.
  • 18. Classification 4/22/2011 18 Inline Class (將類別內聯化) 動機 如果一個class不再承擔足夠的責任,不再有單獨存在的理由。 挑選最頻繁使用這個「萎縮class」的用戶,以Inline Class手法塞進去。 作法 在absorbing class(合併端class)宣告source class的public協定,並將所有函式委託(delegate)至source class. 修改source class的引用點->absorbing class。 Compile and Test Move Method and Move Field,將source class的特性移過去。 幫source class舉行一個簡單的喪禮。
  • 19. Classification 4/22/2011 19 Inline Class (將類別內聯化) 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 { public String getName() {return _name;} public String getTelephoneNumber() {return _officeTelephone.getTelephoneNumber();} TelephoneNumbergetOfficeTelephone() {return _officeTelephone;} private String _name; private TelephoneNumber _officeTelephone = new TelephoneNumber(); String getAreaCode() { return _officeTelephone.getAreaCode();} void setAreaCode(String arg) { _officeTelephone.setAreaCode(arg);} String getNumber() { return _officeTelephone.getNumber();} void setNumber(String arg) { _officeTelephone.setNumber(arg);} }
  • 20. Classification 4/22/2011 20 Inline Class (將類別內聯化) Person martin = new Person(); martin.getOfficeTelephone().setAreaCode ("781"); Person martin = new Person(); martin.setAreaCode ("781");
  • 21. Classification 4/22/2011 21 Hide Delegate (隱藏「委託關係」) 客戶直接呼叫其server object(服務物件)的delegate class。 在Server端建立客戶所需的所有函式,用以隱藏委托關係(delegation)。
  • 22. Classification 4/22/2011 22 Hide Delegate (隱藏「委託關係」) 動機 封裝即使不是物件的最關鍵特徵,也是最關鍵特徵之一。 如果某個客戶呼叫了「建立於server object的某個欄位基礎之上」的函式,客戶就必需知道這個委託物件(delegate object),萬一委託關係發生變化,客戶也得相應變化。 將委託關係隱藏起來,去除這種依存性,將變化限制在server中,不會波及客戶。
  • 23. Classification 4/22/2011 23 Hide Delegate (隱藏「委託關係」) 作法 對每一個委託關係中的函式,在server端建立一個簡單的委託函式(delegating method)。 調整客戶,令它只呼叫server提供的函式 Compile and Test 如果將來不再有任何客戶需要用到Delegate,便可移除server中的存取函式 Compile and Test
  • 24. Classification 4/22/2011 24 Hide Delegate (隱藏「委託關係」) class Person { Department _department; public Department getDepartment() { return _department; } public void setDepartment(Department arg) { _department = arg; } } 範例 manager = john.getDepartment().getManager(); public Person getManager() { return _department.getManager(); } class Department { private String _chargeCode; private Person _manager; public Department(Person manager) { _manager = manager; } public Person getManager() { return _manager; } } manager = john.getManager();
  • 25. Classification 4/22/2011 25 Remove Middle Man (移除中間人) 某個class做了過多的簡單委託動作(simple delegation)。 讓客戶直接呼叫delegate(受託類別)。
  • 26. Classification 4/22/2011 26 Remove Middle Man (移除中間人) 動機 Hide Delegate的代價 當客戶要用到delegate的新特性時,你就必須在server端添加一個簡單委託函式。delegate的特性(功能)愈來愈多,就愈來愈痛苦。 很難說什麼程度的隱藏才是合適的。 隨著系統的變化,改成合適的就好了。 重構的意義就在於:你永遠不必說什麼對不起,只要把出問題的地方修補好就行了。 作法 建立一個函式,用以取代delegate(受托物件)。 對於每個委託函式(delegate method),在server中刪除該函式,並將「客戶對該函式的呼叫」替換為「對delegate的呼叫」。 Compile and Test
  • 27. Classification 4/22/2011 27 Remove Middle Man (移除中間人) 範例 class Person { Department _department; public Person getManager() { return _department.getManager(); } } class Department { private Person _manager; public Department(Person manager) { _manager = manager; } } manager = john.getManager(); class Person { public Department getDepartment() { return _department; } } manager = john.getDepartment().getManager();
  • 28. Classification 4/22/2011 28 Introduce Foreign Method (加入外加函式) 你所使用的server class需要一個函式,但你無法修改這個class。 在client class中建立一個函式,並以一個server class實體作為第一引數(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); }
  • 29. Classification 4/22/2011 29 Introduce Foreign Method (加入外加函式) 動機 你正在使用一個class,它真的很好,為你提供了你想要的所有服務。 當你需要一個新服務,這個class卻無法供應… 如果可以修改源碼,你便可以加一個新函式,如果不能,你就得在客戶端編碼,補足你要的函式。 如果你需要使用很多次,你就得不斷重初這些程式碼… 如果你以外加函式實現一個新功能,那就是一個明確信號: 這個函式原本應該在提供服務的class中加以實現。 如果一個server class加入了大量的外加函式,你就不應該再使用本項重構,而應該使用Introduce Local Extension。
  • 30. Classification 4/22/2011 30 Introduce Foreign Method (加入外加函式) 作法 在client class中建立一個函式,用來提供你需要的功能。 這個函式不應該取用client class的任何特性,如果需要,用參數傳給它。 以server class實體作為該函式的第一個參數。 將該函式注釋為「外加函式(foreign method),應在server class實現。 範例 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); }
  • 31. Classification 4/22/2011 31 Introduce Local Extension (引入區域性擴展) 你所使用的server class需要一些額外函式,但你無法修改這個class。 建立一個新class,使用包含這些額外函式。讓這個擴展品成盥source class的sub class(子類別)或wrapper(外覆類別)。
  • 32. Classification 4/22/2011 32 Introduce Local Extension (引入區域性擴展) 動機 如果只需要一兩個函式,可以使用Introduce Foreign Method。 超果兩個,可以用這個方法將這些函式組織在一起,這種方式稱之為local extension(區域性擴展) 是一個獨立的class,卻也是其extended class的subtype。 堅持「函式和資料應該被包裝在形式良好的單元內」。 如果你一直把本該在extension class的程式零散放在其他classes中,只會讓其他這些classes變得過分複雜,並使得其中函式難以被復用。 local extension有兩種作法 Subclass 必須在物件創建期實施。 必須新增一個class,但是當原物件也被使用時,就要考慮維護兩份資料的問題。 Wrapper 通常首選subclass,因為工作量比較少。
  • 33. Classification 4/22/2011 33 Introduce Local Extension (引入區域性擴展) 作法 建立一個extension class,將它作為原物(原類別)的subclass或wrapper。 在extension class中加入轉型建構式(converting constructors)。 Converting constructors: 接受原物作為參數 在extension class中加入新特性。 根據需要,將原物(original)替換為擴展物(extension)。 將「針對原始類別而定義的所有外加函式(foreign ethods)」搬移到extension class中。
  • 34. Classification 4/22/2011 34 Introduce Local Extension (引入區域性擴展) 範例(Subclass) class MfDateSub extends Date { public MfDateSub (String dateString) { super (dateString); } public MfDateSub (Date arg) { super (arg.getTime()); } Date nextDay() { return new Date (getYear(),getMonth(), getDate() + 1); } } 轉型建構式(converting constructors)
  • 35. Classification 4/22/2011 35 Introduce Local Extension (引入區域性擴展) class MfDateWrap { private Date _original; public MfDateWrap(String dateString) { _original = new Date(dateString); } public MfDateWrap(Date arg) { _original = arg; } // 為原始類別的所有函式提供委託函式… public intgetYear() {return _original.getYear();} public intgetMonth() {return _original.getMonth();} public intgetDate() {return _original.getDate();} public boolean equals(MfDateWraparg) {return (toDate().equals(arg.toDate()));} Date nextDay() { return new Date(getYear(), getMonth(), getDate() + 1); } } 範例(Wrapper) 如何處理「接受原始類別之實體為參數」的函式? 只是執行一個單純的委託動作(delegate) public boolean after (Date arg) aWrapper.after(aDate) aWrapper.after(anotherWrapper) aDate.after(aWrapper)
  • 36. Introduce Local Extension (引入區域性擴展) 範例(Wrapper) 上一頁”after” method這種overriding的目的是為了向用戶隱藏wrapper的存在,這是一個好策略。 不過在某些系統所提供的函式(如equals)會出問題。 public booleanequals (Date arg) // causes problems 這樣做是危險的,因為Java系統的其他部份都認為equals符合交換律:如果a.equals(b)為真,b.equals(a)也必為真。 違反這樣的規則將使我遭遇一大堆莫名其妙的錯誤,但是又無法同時修改Date,所以建議向用戶曝露「我進行了包裝」 public booleanequalsDate(Date arg) public booleanequalsDate(MfDateWraparg) Subclass則不會有這問題,只要不覆寫original class中的函式。 一般來說不會在extension class中覆寫original class的函式,只會添加新函式。 Classification 4/22/2011 36
  • 37. Classification 4/22/2011 37 Summary 決定把責任放在哪兒? 重構的基本手法 Move Field > Move Method Class責任 過多 或是 過少 Extract Class V.S Inline Class Class使用另一Class Hide Delegate將關係隱藏起來 因為Hide delegate導致擁有者的介面經常變化 Remove Middle Man 當我不能存取某個class的源碼,又想把其他責任移進去 Introduce Foreign Method (只加一、二個函式) Introduce Local Extension