前言
最近看了《重構-改善既有代碼的設計》這本書,總結了優化代碼的幾個小技巧,給大家分享一下。
提煉函數(適當抽取小函數)
定義
提煉函數就是將一段代碼放進一個獨立函數中,並讓函數名稱解釋該函數用途。
一個過於冗長的函數或者一段需要註釋才能讓人理解用途的代碼,可以考慮把它切分成一個功能明確的函數單元,並定義清晰簡短的函數名,這樣會讓代碼變得更加優雅。
優化例子
提煉函數之前:
private String name;
private Vector<Order> orders = new Vector<Order>();
public void printOwing() {
//print banner
System.out.println("****************");
System.out.println("*****customer Owes *****");
System.out.println("****************");
//calculate totalAmount
Enumeration env = orders.elements();
double totalAmount = 0.0;
while (env.hasMoreElements()) {
Order order = (Order) env.nextElement();
totalAmount += order.getAmout();
}
//print details
System.out.println("name:" + name);
System.out.println("amount:" + totalAmount);
}
提煉函數之後:
以上那段代碼,可以抽成print banner,calculate totalAmount,print details三個功能的單一函數,如下:
private String name;
private Vector<Order> orders = new Vector<Order>();
public void printOwing() {
//print banner
printBanner();
//calculate totalAmount
double totalAmount = getTotalAmount();
//print details
printDetail(totalAmount);
}
void printBanner(){
System.out.println("****************");
System.out.println("*****customer Owes *****");
System.out.println("****************");
}
double getTotalAmount(){
Enumeration env = orders.elements();
double totalAmount = 0.0;
while (env.hasMoreElements()) {
Order order = (Order) env.nextElement();
totalAmount += order.getAmout();
}
return totalAmount;
}
void printDetail(double totalAmount){
System.out.println("name:" + name);
System.out.println("amount:" + totalAmount);
}
內聯函數(適當去除多餘函數)
定義
內聯函數就是在函數調用點插入函數本體,然後移除該函數。
上一小節介紹了提煉函數代碼優化方式,以簡短清晰的小函數爲榮。但是呢,小函數是不是越多越好呢?肯定不是啦,有時候你會遇到某些函數,其內部代碼和函數名稱同樣清晰,這時候呢你可以考慮內聯函數優化一下了。
優化例子
內聯函數之前
int getRating(){
return moreThanFiveDeliveries() ? 2 : 1;
}
boolean moreThanFiveDeliveries(){
return numberOfLateDeliveries >5;
}
內聯函數之後
int getRating(){
return numberOfLateDeliveries >5 ? 2 : 1;
}
內聯臨時變量(去除多餘臨時變量)
定義
內聯臨時變量將所有對該變量的引用動作,替換爲對它賦值的那個表達式自身。
優化例子
內聯臨時變量之前
double basePice = anOrder.basePrice();
return basePice >888;
內聯臨時變量之後
return anOrder.basePrice() >888;
引入解釋性變量
定義
引入解釋性變量 就是將該複雜表達式(或其中一部分)的結果放進一個臨時變量,以此變量名稱來解釋表達式用途。
有些表達式可能非常複雜難於閱讀,在這種情況下,臨時變量可以幫助你將表達式分解爲可讀的形式。
在比較複雜的條件邏輯中,你可以用引入解釋性變量將每個條件子句提煉出來,以一個良好命名的臨時變量來解釋對應條件子句的意義。
優化例子
引入解釋性變量之前
if ((platform.toUpperCase().indexOf("mac") > -1) &&
(brower.toUpperCase().indexOf("ie") > -1) &&
wasInitializes() && resize > 0) {
......
}
引入解釋性變量之後
final boolean isMacOS = platform.toUpperCase().indexOf("mac") > -1;
final boolean isIEBrowser = brower.toUpperCase().indexOf("ie") > -1;
final boolean wasResized = resize > 0;
if (isMacOS && isIEBrowser && wasInitializes() && wasResized) {
......
}
以字面常量取代魔法數
定義
創造一個常量,根據其意義爲它命名,並將上述的字面數值替換爲這個常量。
所謂魔法數是指擁有特殊意義,卻又不能明確表現出這種意義的數字。如果你需要在不同的地點引用同一個邏輯數,每當該數字要修改時,會特別頭疼,因爲很可能會改漏。而字面常量取代魔法數可以解決這個頭疼問題。
優化例子
以字面常量取代魔法數之前
double getDiscountPrice(double price){
return price * 0.88;
}
以字面常量取代魔法數之後
static final double DISCOUNT_CONSTANT=0.88;
double getDiscountPrice(double price){
return price * DISCOUNT_CONSTANT;
}
用多態替代switch語句
定義
用多態替換switch語句 就是利用Java面向對象的多態特點,使用state模式來替換switch語句。
優化例子
用多態替換switch語句之前
int getArea() {
switch (shape){
case SHAPE.CIRCLE:
return 3.14 * _r * _r; break;
case SHAPE.RECTANGEL;
return width *,heigth;
}
}
用多態替換switch語句之後
class Shape {
int getArea(){};
}
class Circle extends Shape {
int getArea() {
return 3.14 * r * r;
}
}
class Rectangel extends Shape {
int getArea() {
return width * heigth;
}
}
將過多的參數對象化
定義
將過多的參數對象化就是把涉及過多參數封裝成一個對象傳參。
一個方法有太多傳參時,即難以閱讀又難於維護。尤其針對dubbo遠程調用這些方法,如果有過多參數,增加或者減少一個參數,都要修改接口,真的坑。如果把這些參數封裝成一個對象,就很好維護了,不用修改接口。
優化例子
將過多的參數對象化之前:
public int register(String username,String password,Integer age,String phone);
將過多的參數對象化之後:
public int register(RegisterForm from );
class RegisterForm{
private String username;
private String password;
private Integer age;
private String phone;
}
參考與感謝
《重構-改善既有代碼的設計》
個人公衆號
如果你是個愛學習的好孩子,可以關注我公衆號,一起學習討論。
如果你覺得本文有哪些不正確的地方,可以評論,也可以關注我公衆號,私聊我,大家一起學習進步哈。