目錄java
這是一篇《重構 》的總結 ,我在學習的同時並使用它做爲參考。這不是一本書的替代品,因此你要想真的想學習裏面的內容,買一本書使用這個文章做爲參考和指南。git
另外: 建議 評論 還 PR 都是十分歡迎的github
多個地方使用相同的代碼算法
一個很長的程序是很難被理解的數據庫
當一個類變的愈來愈大的時候,是難以閱讀的express
長參數是很難去理解,不符合也較難使用編程
當一個類常常由於不一樣緣由發生在不一樣的方向發生變化數組
每次你作一小部分修改時,都不的不須要作大量的修改在不少不一樣的類中session
某個方法彷佛在另外的類的興趣高於本身所處的類架構
一堆數據雜糅在一塊兒(字段, 參數)
使用基本類型替代小對象
當程序中出現不少 switch 語句在不少地方,使用多態來進行替換
每當你爲一個類增長一個子類,你不得不爲另外一個類增長相應的一個子類
當一個類不足與爲其自身買單它就應該被刪除
全部的鉤子和特殊狀況處理那些不須要的
一個臨時變量僅僅爲某種特殊狀況作而定,這樣的代碼讓人難以理解
當一個類請求調用一個對象,可是這個類又在調用其餘的方法
當一個對象委託大部分功能,開發中可能會過分的使用委託模式,致使某個類中的方法大都委託給其餘方法處理
當兩個類過分的親密,須要將其拆散
類的方法過分類似
當咱們使用外部依賴庫時
不要操做數據類,咱們經過封裝它的不變性
子類不想使用父類的方法
當一個方法使用過分的註釋解釋其中的邏輯時,說明這個方法應該被重構了。
你能夠將一些代碼組合起來,而後放到一個方法中
void printOwing(double amount) { printBanner(); //print details System.out.println ("name:" + _name); System.out.println ("amount" + amount); }
to
void printOwing(double amount) { printBanner(); printDetails(amount); } void printDetails (double amount) { System.out.println ("name:" + _name); System.out.println ("amount" + amount); }
動機
void printOwing(double previousAmount) { Enumeration e = _orders.elements(); double outstanding = previousAmount * 1.2; printBanner(); // calculate outstanding while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } printDetails(outstanding); }
to
void printOwing(double previousAmount) { printBanner(); double outstanding = getOutstanding(previousAmount * 1.2); printDetails(outstanding); } double getOutstanding(double initialValue) { double result = initialValue; Enumeration e = _orders.elements(); while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); result += each.getAmount(); } return result; }
一個函數本體和函數名稱同樣容易理解
int getRating() { return (moreThanFiveLateDeliveries()) ? 2 : 1; } boolean moreThanFiveLateDeliveries() { return _numberOfLateDeliveries > 5; }
to
int getRating() { return (_numberOfLateDeliveries > 5) ? 2 : 1; }
動機
你申明瞭一個臨時的變量在一段表達裏面,而後臨時的變量將會阻擋你重構
double basePrice = anOrder.basePrice(); return (basePrice > 1000)
to
return (anOrder.basePrice() > 1000)
Motivation
你正在使用臨時變量來保存表達式的結果
double basePrice = _quantity * _itemPrice; if (basePrice > 1000){ return basePrice * 0.95; } else{ return basePrice * 0.98; }
to
if (basePrice() > 1000){ return basePrice() * 0.95; } else{ return basePrice() * 0.98; } ... double basePrice() { return _quantity * _itemPrice; }
動機
有一個複雜的表達式
if ( (platform.toUpperCase().indexOf("MAC") > -1) && (browser.toUpperCase().indexOf("IE") > -1) && wasInitialized() && resize > 0 ) { // do something }
to
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) { // do something }
動機
你能有一個臨時變量聲明不止一次,可是它不是循環體中的變量或者要被存儲的變量
double temp = 2 * (_height + _width); System.out.println (temp); temp = _height * _width; System.out.println (temp);
to
final double perimeter = 2 * (_height + _width); System.out.println (perimeter); final double area = _height * _width; System.out.println (area);
動機
下的代碼將對參數進行了賦值
int discount (int inputVal, int quantity, int yearToDate) { if (inputVal > 50) { inputVal -= 2; } }
to
int discount (int inputVal, int quantity, int yearToDate) { int result = inputVal; if (inputVal > 50) { result -= 2; } }
動機
將這個函數放進一個單獨的對象,如此一來局部變量就變成對象內部的字段,而後你能夠在同一個對象中將這個大型函數分解爲多個小型函數
class Order... double price() { double primaryBasePrice; double secondaryBasePrice; double tertiaryBasePrice; // long computation; ... }
to
class Order... double price(){ return new PriceCalculator(this).compute() } } class PriceCalculato... compute(){ double primaryBasePrice; double secondaryBasePrice; double tertiaryBasePrice; // long computation; return ... }
動機
它的樣本本不該該這樣的重構,可是爲顯示這樣作的方法
Class Account int gamma (int inputVal, int quantity, int yearToDate) { int importantValue1 = (inputVal * quantity) + delta(); int importantValue2 = (inputVal * yearToDate) + 100; if ((yearToDate - importantValue1) > 100) importantValue2 -= 20; int importantValue3 = importantValue2 * 7; // and so on. return importantValue3 - 2 * importantValue1; } }
to
class Gamma... private final Account _account; private int inputVal; private int quantity; private int yearToDate; private int importantValue1; private int importantValue2; private int importantValue3; Gamma (Account source, int inputValArg, int quantityArg, int yearToDateArg) { _account = source; inputVal = inputValArg; quantity = quantityArg; yearToDate = yearToDateArg; } int compute () { importantValue1 = (inputVal * quantity) + _account.delta(); importantValue2 = (inputVal * yearToDate) + 100; if ((yearToDate - importantValue1) > 100) importantValue2 -= 20; int importantValue3 = importantValue2 * 7; // and so on. return importantValue3 - 2 * importantValue1; } int gamma (int inputVal, int quantity, int yearToDate) { return new Gamma(this, inputVal, quantity,yearToDate).compute(); }
你想更換一個更爲清晰高效的算法
String foundPerson(String[] people){ for (int i = 0; i < people.length; i++) { if (people[i].equals ("Don")){ return "Don"; } if (people[i].equals ("John")){ return "John"; } if (people[i].equals ("Kent")){ return "Kent"; } } return ""; }
to
String foundPerson(String[] people){ List candidates = Arrays.asList(new String[] {"Don", "John","Kent"}); for (int i = 0; i<people.length; i++) if (candidates.contains(people[i])) return people[i]; return ""; }
動機
在進行方法的初始定義的時候要想下之後會不會有其餘的類也將會用到它
一個類它一般會建立一個新的簡單的方法體, 同時它會將9⃣舊的方法作一個簡單的委託或者移除它
class Class1 { aMethod() } class Class2 { }
to
class Class1 { } class Class2 { aMethod() }
動機
當一個類作了不少工做,或者這個類過分的耦合
當一個字段被定義的時候,可能不只被不止一個類使用。
建立一個字段在一個目標類中,而後改變全部的擁有者
class Class1 { aField } class Class2 { }
to
class Class1 { } class Class2 { aField }
動機
若是一個字段被超過多個類引用
你有一個類,可是這個類作了它份外的事情
建立一個新的類,而後將相關字段移入到新的類中
class Person { name, officeAreaCode, officeNumber, getTelephoneNumber() }
to
class Person { name, getTelephoneNumber() } class TelephoneNumber { areaCode, number, getTelephoneNumber() }
動機
類隨着業務的增加在變化
在合適的時候進行分解它
一個其實沒作多少事情的類
將這個類整合到另一個類中,而後刪除這個類
class Person { name, getTelephoneNumber() } class TelephoneNumber { areaCode, number, getTelephoneNumber() }
to
class Person { name, officeAreaCode, officeNumber, getTelephoneNumber() }
動機
在重構的時候將這個類的基本信息移入到另一個類中,而後在移除這個類
客戶端其實調用的是對象的委託類
在服務端建立一個方法,而後隱藏這個委託類
class ClientClass { //Dependencies Person person = new Person() Department department = new Department() person.doSomething() department.doSomething() }
to
class ClientClass { Person person = new Person() person.doSomething() } class Person{ Department department = new Department() department.doSomething() }
解決方法
class ClientClass{ Server server = new Server() server.doSomething() } class Server{ Delegate delegate = new Delegate() void doSomething(){ delegate.doSomething() } } //委託類其實隱藏在客戶類裏面 // 改變不會傳播到客戶端那邊,由於它以後影響到服務端這邊 class Delegate{ void doSomething(){...} }
動機
關鍵在於封裝
類應該儘可能的使用其餘的類
> manager = john.getDepartment().getManager();
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; } ...
to
> manager = john.getManager();
class Person { ... public Person getManager() { return _department.getManager(); } }
一個類經過代理幹了太多的事情
讓客戶直接調用委託
class ClientClass { Person person = new Person() person.doSomething() } class Person{ Department department = new Department() department.doSomething() }
to
class ClientClass { //Dependencies Person person = new Person() Department department = new Department() person.doSomething() department.doSomething() }
動機
當客戶類使用過多的中間人調用委託的方法
一個類是引用的外部開源包,可是不能修改其內部的邏輯
建立一個新的方法在這個類中,並以第一個參數的形式傳入一個服務類實例
Date newStart = new Date(previousEnd.getYear(),previousEnd.getMonth(),previousEnd.getDate()+1);
to
Date newStart = nextDay(previousEnd); private static Date nextDay(Date date){ return new Date(date.getYear(),date.getMonth(),date.getDate()+1); }
動機
當你使用一個類,這個類你又不能對其進行修改的時候能夠採用這樣方式
你須要爲一個服務類提供一些額外的方法,可是你沒法修改這個子類
建立一個新的類,使它包含這些額外的方法。這個擴展的類成爲源類的子類或者包裝類
class ClientClass(){ Date date = new Date() nextDate = nextDay(date); private static Date nextDay(Date date){ return new Date(date.getYear(),date.getMonth(),date.getDate()+1); } }
to
class ClientClass() { MfDate date = new MfDate() nextDate = nextDate(date) } class MfDate() extends Date { ... private static Date nextDay(Date date){ return new Date(date.getYear(),date.getMonth(),date.getDate()+1); } }
動機
當咱們使用 16. Introduce Foreign Method 咱們須要在這個類中添加額外的方法
你能夠直接獲取對象,可是這樣的話會變得愈來愈複雜
經過建立setting getting 方法來獲取這些字段
private int _low, _high; boolean includes (int arg) { return arg >= _low && arg <= _high; }
to
private int _low, _high; boolean includes (int arg) { return arg >= getLow() && arg <= getHigh(); } int getLow() {return _low;} int getHigh() {return _high;}
動機
容許子類能夠覆蓋如何get方法,而且這樣的話它更加的支持靈活的管理,例如延遲加載
當你有個數據項須要進行添加數據或行爲
將數據項轉換爲對象
class Order...{ private String _customer; public Order (String customer) { _customer = customer; } }
to
class Order...{ public Order (String customer) { _customer = new Customer(customer); } } class Customer { public Customer (String name) { _name = name; } }
動機
簡單的數據對象並不簡單
你有個類擁有不少單個對象,這些對象須要用一個單獨的對象替代
將這個對象轉換爲引用對象
class Order...{ public Order (String customer) { _customer = new Customer(customer); } } class Customer { public Customer (String name) { _name = name; } }
to
//Use Factory Method //使用工廠方法 class Customer... static void loadCustomers() { new Customer ("Lemon Car Hire").store(); new Customer ("Associated Coffee Machines").store(); new Customer ("Bilston Gasworks").store(); } private void store() { _instances.put(this.getName(), this); } public static Customer create (String name) { return (Customer) _instances.get(name); }
動機
引用對象是相似於消費者或者帳單這樣的對象,每一個對象表明這一類對象在一個真實的世界,並使用對象表示來測試它們是否相同
你有一個有一個引用對象是很小,不變,難以管理的
將其轉換爲值對象
new Currency("USD").equals(new Currency("USD")) // returns false
to
new Currency("USD").equals(new Currency("USD")) // now returns true
動機
使用引用對象是變得越來月複雜,而且引用對象是不變和單一的。尤爲在分佈式和併發系統中
你擁有一個數組,其中這些元素是不一樣的
使用一個對象來替換這個數組,將數組的元素賦值在對象的屬性上
String[] row = new String[3]; row [0] = "Liverpool"; row [1] = "15";
to
Performance row = new Performance(); row.setName("Liverpool"); row.setWins("15");
動機
數組應該被用在一些類似的集合對象序列中
可能你有一些domain數據是經過GUI控制的與此同時這些domain數據是須要訪問的
往一些實體對象複製一些數據,經過設置觀察者來同步兩部分數據
動機
爲了將代碼從用戶界面分解到業務處理層
你有兩個對象,這兩個對象須要使用對方的特徵屬性,可是目前只有一種鏈接方式
添加返回指針,而後更改修飾符已更改兩個對象
class Order... Customer getCustomer() { return _customer; } void setCustomer (Customer arg) { _customer = arg; } Customer _customer; }
to
class Order... Customer getCustomer() { return _customer; } void setCustomer (Customer arg) { if (_customer != null) _customer.friendOrders().remove(this); _customer = arg; if (_customer != null) _customer.friendOrders().add(this); } private Customer _customer; class Customer... void addOrder(Order arg) { arg.setCustomer(this); } private Set _orders = new HashSet(); Set friendOrders() { /** should only be used by Order */ return _orders; } } } // Many to Many class Order... //controlling methods void addCustomer (Customer arg) { arg.friendOrders().add(this); _customers.add(arg); } void removeCustomer (Customer arg) { arg.friendOrders().remove(this); _customers.remove(arg); } class Customer... void addOrder(Order arg) { arg.addCustomer(this); } void removeOrder(Order arg) { arg.removeCustomer(this); } }
動機
當對象引用須要互相引用的時候,你應該採用這種方法
當你有個雙向聯繫的類,可是在後期一個類不在須要另外一個類中的屬性了
扔掉不須要的聯繫
動機
當雙向聯繫不在須要,減小複雜度,移除殭屍對象,消除相互依賴
你有一個特定含義的字符串
建立一個常量,名稱根據它的意思命名而後替換那個數字
double potentialEnergy(double mass, double height) { return mass * 9.81 * height; }
to
double potentialEnergy(double mass, double height) { return mass * GRAVITATIONAL_CONSTANT * height; } static final double GRAVITATIONAL_CONSTANT = 9.81;
動機
避免使用魔法數字
這裏有一個公共的字段
將它改成私有的並提供訪問函數
public String _name
to
private String _name; public String getName() { return _name; } public void setName(String arg) { _name = arg; }
動機
你應該將你數據公開
一個返回幾個的方法
確保返回一個只讀的影像對象,而後提供添加和移除方法
class Person { Person (String name){ HashSet set new HashSet() } Set getCourses(){} void setCourses(:Set){} }
to
class Person { Person (String name){ HashSet set new HashSet() } Unmodifiable Set getCourses(){} void addCourses(:Course){} void removeCourses(:Course){} }
動機
你必須面對一個記錄值在傳統的編程環境中
使用一個殭屍數據對象代替記錄值
動機
一個類擁有數字類別碼,不能影響其行爲
使用類來代替數字
class Person{ O:Int; A:Int; B:Int; AB:Int; bloodGroup:Int; }
to
class Person{ bloodGroup:BloodGroup; } class BloodGroup{ O:BloodGroup; A:BloodGroup; B:BloodGroup; AB:BloodGroup; }
動機
靜態類別檢查
在一個類中擁有一個不變的類型碼影響整個類的行爲
使用子類來替代這個不變的類型碼
class Employee... private int _type; static final int ENGINEER = 0; static final int SALESMAN = 1; static final int MANAGER = 2; Employee (int type) { _type = type; } }
to
abstract int getType(); static Employee create(int type) { switch (type) { case ENGINEER: return new Engineer(); case SALESMAN: return new Salesman(); case MANAGER: return new Manager(); default: throw new IllegalArgumentException("Incorrect type code value"); } }
動機
在類中有個類型碼,並經過這個類型碼來影響行爲,可是你不能使用子類
經過狀態對象來代替這個類型碼
class Employee { private int _type; static final int ENGINEER = 0; static final int SALESMAN = 1; static final int MANAGER = 2; Employee (int type) { _type = type; } int payAmount() { switch (_type) { case ENGINEER: return _monthlySalary; case SALESMAN: return _monthlySalary + _commission; case MANAGER: return _monthlySalary + _bonus; default: throw new RuntimeException("Incorrect Employee"); } } } }
to
class Employee... static final int ENGINEER = 0; static final int SALESMAN = 1; static final int MANAGER = 2; void setType(int arg) { _type = EmployeeType.newType(arg); } class EmployeeType... static EmployeeType newType(int code) { switch (code) { case ENGINEER: return new Engineer(); case SALESMAN: return new Salesman(); case MANAGER: return new Manager(); default: throw new IllegalArgumentException("Incorrect Employee Code"); } } } int payAmount() { switch (getType()) { case EmployeeType.ENGINEER: return _monthlySalary; case EmployeeType.SALESMAN: return _monthlySalary + _commission; case EmployeeType.MANAGER: return _monthlySalary + _bonus; default: throw new RuntimeException("Incorrect Employee"); } } }
動機
你的子類僅在返回常數變量數據變量的方法中有所不一樣
將這個方法提高到父類中,並移除這個子類
abstract class Person { abstract boolean isMale(); abstract char getCode(); ... } class Male extends Person { boolean isMale() { return true; } char getCode() { return 'M'; } } class Female extends Person { boolean isMale() { return false; } char getCode() { return 'F'; } }
to
class Person{ protected Person (boolean isMale, char code) { _isMale = isMale; _code = code; } boolean isMale() { return _isMale; } static Person createMale(){ return new Person(true, 'M'); } static Person createFemale(){ return new Person(false, 'F'); } }
動機
你有一個複雜的條件(大量的if else then )
使用額外的方法代替這個表達式,將then 放在一部分,else 放在一部分
if (date.before (SUMMER_START) || date.after(SUMMER_END)) charge = quantity * _winterRate + _winterServiceCharge; else charge = quantity * _summerRate;
to
if (notSummer(date)) charge = winterCharge(quantity); else charge = summerCharge (quantity);
動機
double disabilityAmount() { if (_seniority < 2) return 0; if (_monthsDisabled > 12) return 0; if (_isPartTime) return 0; // compute the disability amount
to
double disabilityAmount() { if (isNotEligableForDisability()) return 0; // compute the disability amount
在條件表達式的每一個分支上有着相同的一片代碼
將這段重複代搬移到條件表達式以外
if (isSpecialDeal()) { total = price * 0.95; send(); } else { total = price * 0.98; send(); }
to
if (isSpecialDeal()) { total = price * 0.95; } else { total = price * 0.98; } send();
動機
使得變量清晰並保持相同
在一系列的布爾表達式中,某個變量帶有「控制標記」的做用
已break或者return語句取代控制標記
void checkSecurity(String[] people) { boolean found = false; for (int i = 0; i < people.length; i++) { if (! found) { if (people[i].equals ("Don")){ sendAlert(); found = true; } if (people[i].equals ("John")){ sendAlert(); found = true; } } } }
to
void checkSecurity(String[] people) { for (int i = 0; i < people.length; i++) { if (people[i].equals ("Don")){ sendAlert(); break; // or return } if (people[i].equals ("John")){ sendAlert(); break; // or return } } }
動機
break
和 continue
函數的條件邏輯令人難以看清正常的執行路徑
使用衛語句表現全部的特殊狀況
double getPayAmount() { double result; if (_isDead) result = deadAmount(); else { if (_isSeparated) result = separatedAmount(); else { if (_isRetired) result = retiredAmount(); else result = normalPayAmount(); }; } return result; };
to
double getPayAmount() { if (_isDead) return deadAmount(); if (_isSeparated) return separatedAmount(); if (_isRetired) return retiredAmount(); return normalPayAmount(); };
動機
你手上有一個條件表達式,它根據對象的類型的不一樣選擇不一樣的行爲
將條件表達式的全部分支放進一個子類內的覆蓋函數中,而後將原始函數聲明爲抽象函數
class Employee { private int _type; static final int ENGINEER = 0; static final int SALESMAN = 1; static final int MANAGER = 2; Employee (int type) { _type = type; } int payAmount() { switch (_type) { case ENGINEER: return _monthlySalary; case SALESMAN: return _monthlySalary + _commission; case MANAGER: return _monthlySalary + _bonus; default: throw new RuntimeException("Incorrect Employee"); } } } }
to
class Employee... static final int ENGINEER = 0; static final int SALESMAN = 1; static final int MANAGER = 2; void setType(int arg) { _type = EmployeeType.newType(arg); } int payAmount() { return _type.payAmount(this); } } class Engineer... int payAmount(Employee emp) { return emp.getMonthlySalary(); } }
動機
你不得不檢查對象是否爲Null對象
將null值替換爲null對象
if (customer == null){ plan = BillingPlan.basic(); } else{ plan = customer.getPlan(); }
to
class Customer { } class NullCusomer extends Customer { }
動機
某段代碼須要對程序狀態作出某種假設
已斷言明確表現這種假設
double getExpenseLimit() { // should have either expense limit or a primary project return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); }
to
double getExpenseLimit() { Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null); return (_expenseLimit != NULL_EXPENSE) ? _expenseLimit: _primaryProject.getMemberExpenseLimit(); }
動機
函數的名稱不能表達函數的用途
修改函數名稱
getinvcdtlmt()
to
getInvoiceableCreditLimit
動機
函數的名稱最好能表達函數的意圖
某個函數須要從調用端獲得更多的信息
爲此函數添加一個對象函數,讓改對象帶進函數所須要信息
getContact()
to
getContact(:Date)
動機
在改變方法以後,你得到更多的信息
一個參數不在函數中使用了
移除它
getContact(:Date)
to
getContact()
動機
一個參數再也不使用還留着它幹嗎?
某個函數即返回函數的狀態值,又修改對象的狀態
建立兩個不一樣的函數,其中一個負責查詢,另外一個負責修改
getTotalOutStandingAndSetReadyForSummaries()
to
getTotalOutStanding() SetReadyForSummaries()
動機
將有反作用的方法和沒有反作用的方法分開
若干函數作了相似的工做,但在函數本體中卻包含了不一樣的值
建立單一函數,已參數表達那些不一樣的值
fivePercentRaise() tenPercentRaise()
to
raise(percentage)
動機
移除重複的代碼提升靈活度
🈶一個函數,其中徹底取決於參數值而採起不一樣的行爲
針對該函數的每個可能值,創建一個獨立函數
void setValue (String name, int value) { if (name.equals("height")){} _height = value; return; } if (name.equals("width")){ _width = value; return; } Assert.shouldNeverReachHere(); }
to
void setHeight(int arg) { _height = arg; } void setWidth (int arg) { _width = arg; }
動機
你從某個對象支行取出若干值,將他們做爲某一次函數調用時的參數
改成傳遞一整個對象
int low = daysTempRange().getLow(); int high = daysTempRange().getHigh(); withinPlan = plan.withinRange(low, high);
to
withinPlan = plan.withinRange(daysTempRange());
動機
對象調用某個函數,並將其所得的結果做爲參數,傳遞給另外一個函數。而接受該參數的函數自己也可以調用錢一個函數
將函數接受者去除該項參數,並直接調用前一個函數
int basePrice = _quantity * _itemPrice; discountLevel = getDiscountLevel(); double finalPrice = discountedPrice (basePrice, discountLevel);
to
int basePrice = _quantity * _itemPrice; double finalPrice = discountedPrice (basePrice);
動機
某些參數老是很天然的同時出現
以一個對象取代這些參數
class Customer{ amountInvoicedIn (start : Date, end : Date) amountReceivedIn (start : Date, end : Date) amountOverdueIn (start : Date, end : Date) }
to
class Customer{ amountInvoicedIn (: DateRange) amountReceivedIn (: DateRange) amountOverdueIn (: DateRange) }
動機
類中的某個字段應該在對象建立時被設值,而後就再也不改變
去掉該字段的全部設值函數
class Employee{ setImmutableValue() }
to
class Employee{ ¯\_(ツ)_/¯ }
動機
確保你的清晰的目的 : 若是你想你的字段在建立以後就不要被改變了,你就不該該提供一個setting方法用於確保你的字段是否不被改變的
有一個函數,歷來沒有被其餘任何類用到
將這個函數修改成 private
class Employee{ public method() }
to
class Employee{ private method() }
動機
若是一個方法不須要被外部調用,那麼就應該講這個方法隱藏
在建立對象時不只僅是作簡單的健夠動做
將構造函數替換爲工廠函數
Employee (int type) { _type = type; }
to
static Employee create(int type) { return new Employee(type); }
建立一個對象依賴於其子類,構造函數只能返回單一類型的對象,所以你須要將構造函數替換爲一個工廠函數
某個函數返回的對象,須要由調用者執行向下轉型
將向下轉型動做轉移到函數中
Object lastReading() { return readings.lastElement(); }
to
Reading lastReading() { return (Reading) readings.lastElement(); }
動機
將一個方法最有效的返回值進行返回給函數的調用者
若是類型是準確的,檢查使用這個對象的方法並提供一個更爲有效的方法
某個函數返回一個特定的代碼,用以表示某種錯誤狀況
改用異常將其拋出去
int withdraw(int amount) { if (amount > _balance) return -1; else { _balance -= amount; return 0; } }
to
void withdraw(int amount) throws BalanceException { if (amount > _balance) throw new BalanceException(); _balance -= amount; }
動機
當一個程序在發生了一個不可處理的錯誤時,你須要使這個函數的調用者知道。向上拋出異常,讓上層調用者知道
面對一個調用者能夠預先檢查的條件,你拋出了一個異常
修改調用者,使它在調用函數以前先作檢查
double getValueForPeriod (int periodNumber) { try { return _values[periodNumber]; } catch (ArrayIndexOutOfBoundsException e) { return 0; } }
to
double getValueForPeriod (int periodNumber) { if (periodNumber >= _values.length) return 0; return _values[periodNumber]; }
動機
兩個子類擁有相同的字段
將該字段移到超類中
class Salesman extends Employee{ String name; } class Engineer extends Employee{ String name; }
to
class Employee{ String name; } class Salesman extends Employee{} class Engineer extends Employee{}
動機
你在各個子類中擁有一些構造函數,他們的本體幾乎徹底一致
在超類中新建一個構造函數,並在子類構造函數中調用它
class Salesman extends Employee{ String getName(); } class Engineer extends Employee{ String getName(); }
to
class Employee{ String getName(); } class Salesman extends Employee{} class Engineer extends Employee{}
動機
在子類中的構造函數與父類中的構造函數是相同的
在超類中建立一個構造函數,並在子類構造函數中調用它
class Manager extends Employee... public Manager (String name, String id, int grade) { _name = name; _id = id; _grade = grade; }
to
public Manager (String name, String id, int grade) { super (name, id); _grade = grade; }
動機
父類的某個方法至於某個子類相關
將其移到子類中
class Employee{ int getQuota(); } class Salesman extends Employee{} class Engineer extends Employee{}
to
class Salesman extends Employee{ int getQuota(); } class Engineer extends Employee{}
動機
當方法只在子類中顯現
超類的字段只在某個子類中用到
將這個字段移到須要它的那些子類中去
class Employee{ int quota; } class Salesman extends Employee{} class Engineer extends Employee{}
to
class Salesman extends Employee{ int quota; } class Engineer extends Employee{}
動機
當一個字段只在子類中使用時
類中的某些特性只被某些實例用到
新建一個子類,將上面所說的那一部分特性移到子類中去
class JobItem { getTotalPrices() getUnitPrice() getEmployee() }
to
JobItem { getTotalPrices() getUnitPrice() } class class LabotItem extends JobItem { getUnitPrice() getEmployee() }
動機
當一個類的行爲只用在某些實例中而不用在其餘類中
兩個類具備類似特性
建立一個父類,而後將這兩個類中相同的部分移到父類中,而後在繼承這個父類
class Department{ getTotalAnnualCost() getName() getHeadCount } class Employee{ getAnnualCost() getName() getId }
to
class Party{ getAnnualCost() getName() } class Department { getAnnualCost() getHeadCount } class Employee { getAnnualCost() getId }
動機
當兩個類有過多類似的地方的時候,就須要考慮下是否須要將這個類進行下抽象了
若干客戶使用類接口中的同一個子類,或者兩個類的接口有相同的部分
將相同的子集提煉到一個獨立接口中
class Employee { getRate() hasSpecialSkill() getName() getDepartment() }
to
interface Billable { getRate() hasSpecialSkill() } class Employee implements Billable { getRate hasSpecialSkill() getName() getDepartment() }
動機
超類和子類無太大區別
將它們合爲一個
class Employee{ } class Salesman extends Employee{ }
to
class Employee{ }
動機
該子類沒有帶來任何價值
有些子類,其中對應的某些函數以相同順序執行相似的操做,但各個操做的細節上有所不一樣
將這些操做分別放進獨立函數中,並保持它們都有相同的簽名,因而原函數也就變得相同了。而後將原函數上移到超類
class Site{} class ResidentialSite extends Site{ getBillableAmount() } class LifelineSite extends Site{ getBillableAmount() }
to
class Site{ getBillableAmount() getBaseAmount() getTaxAmount() } class ResidentialSite extends Site{ getBaseAmount() getTaxAmount() } class LifelineSite extends Site{ getBaseAmount() getTaxAmount() }
動機
某個子類只使用了超類接口中的一部分,或是根本不須要繼承而來的數據
_在子類中建立一個字段用以保存超類,調整子類函數,令它改2而委託超類:而後去除二者之間的繼承關係
class Vector{ isEmpty() } class Stack extends Vector {}
to
class Vector { isEmpty() } class Stack { Vector vector isEmpty(){ return vector.isEmpty() } }
動機
你在兩個類之間使用簡單的委託關係,並常常爲整個接口編寫許多不少簡單的委託函數
讓委託類繼承委託類
class Person { getName() } class Employee { Person person getName(){ return person.getName() } }
to
class Person{ getName() } class Employee extends Person{}
動機
某個繼承體系同時承擔兩項責任
創建兩個繼承體系,並經過委託關係讓其中一個能夠調用另一個
class Deal{} class ActiveDeal extends Deal{} class PassiveDeal extends Deal{} class TabularActiveDeal extends ActiveDeal{} class TabularPassiveDeal extends PassiveDeal{}
to
class Deal{ PresentationStyle presettationStyle; } class ActiveDeal extends Deal{} class PassiveDeal extends Deal{} class PresentationStyle{} class TabularPresentationStyle extends PresentationStyle{} class SinglePresentationStyle extends PresentationStyle{}
動機
你手上有些傳統過程化風格的代碼
將數據記錄變成對象,將大塊的行爲分紅小塊,並將行爲移入相關對象中
class OrderCalculator{ determinePrice(Order) determineTaxes(Order) } class Order{} class OrderLine{}
to
class Order{ getPrice() getTaxes() } class OrderLine{ getPrice() getTaxes() }
動機
使用面向對象思想進行變成
某些GUI類中包含了領域邏輯
將領域邏輯分離出來嗎,爲他們建立獨立的領域類
class OrderWindow{}
to
class OrderWindow{ Order order; }
動機
有某個類作了太多的工做其中一部分工做是以大量的條件表達式完成的
建立一個繼承體系,已一個子類來表達某一種特殊的狀況
class BillingScheme{}
to
class BillingScheme{} class BusinessBillingScheme extends BillingScheme{} class ResidentialBillingScheme extends BillingScheme{} class DisabilityBillingScheme extends BillingScheme{}
動機