1. 为何重构
重构改善软件设计,让代码易于理解
重构帮助找到bug
重构提高编程速度
2. 何时重构
三次法则,事不过三,三则重构
添加新功能时重构
修补错误时重构
review代码时重构
3. 坏代码
Duplicated Code(重复代码)
Long Method(函数过长)
Large Class(大类)
Long Parameter List(参数过多)
So on
4. 准备工作 4.1 构建测试环境(重要) 5. 重构方法 5.1 重新组织函数 5.1.1 例子1:(提炼函数) 1 2 3 4 5 6 7 void printOwing (double amount) { printBanner(); System.out.println("name:" + _name); System.out.println("amount:" + _amount); }
改成
1 2 3 4 5 6 7 8 void printOwing (double amount) { printBanner(); printDetails(amount); } void printDetails (double amount) { System.out.println("name:" + _name); System.out.println("amount:" + _amount); }
5.1.2 例子2:(以查询代替临时变量) 1 2 3 4 5 6 7 double getPrice () { int basePrice = _quantity * _itemPrice; double discountFactor; if (basePrice > 1000 ) discountFactor = 0.95 ; else discountFactor = 0.98 ; return basePrice * discountFactor; }
改成
1 2 3 4 5 6 7 8 9 10 11 private int basePrice () { return _quantity * _itemPrice; } private double discountFactor () { if (basePrice() > 1000 ) return 0.95 ; else return 0.98 ; } double getPrice () { return basePrice() * discountFactor(); }
5.1.3 例子3:(引入解释性变量) 1 2 3 4 5 6 if ( (platform.toUpperCase().indexOf("MAC" ) > -1 ) && (browser.toUpperCase().indexOf("IE" ) > -1 ) && { wasInitialized() && resize > 0 ) }
改为:
1 2 3 4 5 6 final boolean isMacOs = platform.toUpperCase().indexOf("MAC" ) > -1 ; final boolean isIEBrowser = browser.toUpperCase().indexOf("IE" ) > -1 ;final boolean wasResized = resize > 0 ;if (isMacOs && isIEBrowser && wasInitialized() && wasResized) { }
1 2 3 4 5 double price () { Math.max(0 , _quantity - 500 ) * _itemPrice * 0.05 + Math.min(_quantity * _itemPrice * 0.1 , 100.0 ); }
改为
1 2 3 4 5 6 7 8 9 10 11 12 double price () { return basePrice() - quantityDiscount() + shipping(); } private double quantityDiscount () { return Math.max(0 , _quantity - 500 ) * _itemPrice * 0.05 ; } private double shipping () { return Math.min(basePrice() * 0.1 , 100.0 ); } private double basePrice () { return _quantity * _itemPrice; }
5.1.4 例子4:(以函数对象取代函数) 1 2 3 4 5 6 7 class Order ... double price () { double primaryBasePrice; double secondaryBasePrice; double tertiaryBasePrice; }
改成:
1 2 Order return new PriceCalculator (this ).compute()
原理就是利用代理类来进行计算
5.2 在对象之间搬移特性 5.2 1 搬移函数 将一个类的函数搬移到另外一个类中,需要增加委托类
5.2.2 搬移字段 将一个类的字段搬移到另外一个类中,我想把表示利率的_interestRate搬移到AccountType class去
1 2 3 4 5 6 class Account ... private AccountType _type; private double _interestRate; double interestForAmount_days (double amount, int days) { return _interestRate * amount * days / 365 ; }
改成
1 2 3 4 5 6 7 8 9 10 11 12 13 class AccountType ... private double _interestRate; void setInterestRate (double arg) { _interestRate = arg; } double getInterestRate () { return _interestRate; } private double _interestRate; double interestForAmount_days (double amount, int days) { return _type.getInterestRate() * amount * days / 365 ; }
5.2.3 提炼类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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;
因为后续TelephoneNumber可能会有扩展,因此将此提炼成一个类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 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); } 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;
5.2.3 将类内联化 是提炼类的反过程
5.2.4 隐藏Delegate 某些时候,一个功能要经过好多层委托,最后才能看到最终的实现,如果委托链过长,显然是会影响代码阅读的。一条有用的经验是委托层级不能超过三层。
5.3 重新组织数据 5.3.1 以对象取代数据值 1 2 3 4 5 6 7 8 9 10 11 class Order ... public Order (String customer) { _customer = customer; } public String getCustomer () { return _customer; } public void setCustomer (String arg) { _customer = arg; } private String _customer;
改为,修改之后的代码扩展更加方便。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Customer { public Customer (String name) { _name = name; } public String getName () { return _name; } private final String _name; } class Order ... public Order (String customer) { _customer = new Customer (customer); } “ public String getCustomer () { return _customer.getName(); } private Customer _customer; public void setCustomer (String arg) { _customer = new Customer (customer); }
5.3.2 以对象取代数组 5.3.3 以符号常量/字面常量取代魔法数 5.4 简化条件表达式(重要) 5.4.1 分解条件式 1 2 3 if (date.before (SUMMER_START) || date.after(SUMMER_END)) charge = quantity * _winterRate + _winterServiceCharge; else charge = quantity * _summerRate;
改为
1 2 3 4 5 6 7 8 9 10 11 12 if (notSummer(date)) charge = winterCharge(quantity); else charge = summerCharge (quantity); private boolean notSummer (Date date) { return date.before (SUMMER_START) || date.after(SUMMER_END); } private double summerCharge (int quantity) { return quantity * _summerRate; } private double winterCharge (int quantity) { return quantity * _winterRate + _winterServiceCharge; }
5.4.2 合并条件式 1 2 3 4 5 6 double disabilityAmount () { if (_seniority < 2 ) return 0 ; if (_monthsDisabled > 12 ) return 0 ; if (_isPartTime) return 0 ; ...
改成
1 2 3 4 double disabilityAmount () { if ((_seniority < 2 ) || (_monthsDisabled > 12 ) || (_isPartTime)) return 0 ; ...
5.4.3 以卫语句取代嵌套条件式 1 2 3 4 5 6 7 8 9 10 11 12 double getPayAmount () { double result; if (_isDead) result = deadAmount(); else { if (_isSeparated) result = separatedAmount(); else { if (_isRetired) result = retiredAmount(); else result = normalPayAmount(); }; } return result; };
改为
1 2 3 4 5 6 double getPayAmount () { if (_isDead) return deadAmount(); if (_isSeparated) return separatedAmount(); if (_isRetired) return retiredAmount(); return normalPayAmount(); };
5.5 简化函数调用 5.6 处理概括关系 5.7 大型重构