当前位置

网站首页> 程序设计 > 开源项目 > 程序开发 > 浏览文章

《Refactoring》: 重新组织函数 - beanlam

作者:小梦 来源: 网络 时间: 2024-02-23 阅读:

Extract Method(提炼函数)

package io.beansoft.refactory.reorganizemethod;import java.util.ArrayList;import java.util.List;/** * * * @author Bean * @date 2016年1月13日 下午5:49:50 * @version 1.0 * */public class ExtractMethod {    // original    void printOwing0() {        List<Integer> list = new ArrayList<Integer>();        double outstanding = 0.0;    //print banner        System.out.println("**************************");        System.out.println("***Customer Owes**********");        System.out.println("**************************");    // calculate outstanding        for (int num : list) {outstanding += num;        }    //print details        System.out.println("**************************");        System.out.println("amount:" + outstanding);        System.out.println("**************************");    }        //没有局部变量    void printOwing1() {        List<Integer> list = new ArrayList<Integer>();        double outstanding = 0.0;    printBanner();    // calculate outstanding        for (int num : list) {outstanding += num;        }    //print details        System.out.println("**************************");        System.out.println("amount:" + outstanding);        System.out.println("**************************");    }//有局部变量    void printOwing2() {        List<Integer> list = new ArrayList<Integer>();        double outstanding = 0.0;    printBanner();    // calculate outstanding        for (int num : list) {outstanding += num;        }    printDetails(outstanding);    }        //对局部变量再赋值    void printOwing3() {        double outstanding = 0.0;    printBanner();    outstanding = getOutstanding();    printDetails(outstanding);    }        double getOutstanding() {        double result = 0.0;        List<Integer> list = new ArrayList<Integer>();     // calculate outstanding        for (int num : list) {result += num;        }        return result;    }        void printDetails(double outstanding) {        //print outstanding        System.out.println("**************************");        System.out.println("amount:" + outstanding);        System.out.println("**************************");    }        void printBanner() {        //print banner        System.out.println("**************************");        System.out.println("***Customer Owes**********");        System.out.println("**************************");    }}

Inline Method(内联函数)

一个函数的本体与名称同样清楚易懂时使用

package io.beansoft.refactory.reorganizemethod;/** * * * @author Bean * @date 2016年1月13日 下午6:07:43 * @version 1.0 * */public class InlineMethod {    private int _numberOfLateDeliveries = 0;        int getRating() {        return moreThanFiveLateDeliveries() ? 2 : 1;    }        boolean moreThanFiveLateDeliveries() {        return _numberOfLateDeliveries > 5;    }//重构后的版本        int getRating0() {        return (_numberOfLateDeliveries > 5) ? 2 : 1;    }}

Inline Temp(内联临时变量)

你有一个临时变量,只被一个简单表达式赋值一次,而它妨碍了其他重构手法,比如Extract Method。

double basePrice = anOrder.basePrice();return (basePrice > 1000);//重构后return (anOrder.basePrice() > 1000);

Replace Temp with Query(以查询取代临时变量)

你的程序以一个临时变量保存某一表达式的运算结果

double basePrice = quantity * itemPrice;if (basePrice > 1000) {    return basePrice * 0.95;} else {    return basePrice * 0.98;}//重构后if (basePrice() > 1000) {    return basePrice() * 0.95;} else {    return basePrice() * 0.98;}double basePrice() {    return quantity * itemPrice;}

关于性能的问题如何考虑,如果basePrice()造成了性能低下,则把临时变量放回去

Introduce Explaining Variable(引入解释性变量)

你有一个复杂的表达式

if ((platform.toUpperCase().indexOf("MAC") > -1) && (browser.toUpperCase().indexOf("IE") > -1) && wasInitialized() && resize > 0 ) {    // do something}//重构后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}

Split Temporary Variable(分解临时变量)

你的程序有某个临时变量被赋值超过一次,它既不是循环变量,也不被用于收集计算结果

针对每次赋值,创造一个独立、对应的临时变量。

double temp = 2 * (height * width);System.out.println(temp);temp = height * width;System.out.println(temp);//重构后final double perimeter = 2 * (height * width);System.out.println(perimeter);final double area = height * width;System.out.println(area);

一个临时变量如果被赋值超过一次,就意味着它在函数中承担了一个以上的责任,就应该被分解为多个临时变量。
同一个临时变量承担两件不同的事情,会令代码阅读者糊涂。

Remove Assignments to Parameters(移除对参数的赋值)

代码对一个参数进行赋值

应该以一个临时变量取代该参数的位置。

int discount(int inputVal, int quantity, int yearToDate) {    if (inputVal > 50) {        inputVal -= 2;    }    }//重构后int discount(int inputVal, int quantity, int yearToDate) {    int result = inputVal;    if (result > 50) {        result -= 2;    }    }

如果把一个名为foo的对象作为参数传递给某个函数,那么"对参数赋值"将会改变foo,使其引用另一个对象。
但这会降低代码的清晰度。而且之后如果在foo上进行操作,将不会改变原来的对象。
在Java中,参数传递是按值传递的。

Replace Method with Method Object(以函数对象取代函数)

如果你有一个大型函数,并且对局部变量的使用是你无法采用Extract Method对其重构

那么你应该将这个函数放进一个单独的对象中,如此一来局部变量就成了对象内的字段。
然后可以在同一个对象中将这个大型函数分解为多个小型函数(函数的入参也会当做对象内的字段)。

public class Account {    public int calculate(int basePrice, double discount, int quantity) {        int tempValue1 = basePrice * quantity + factor();        int tempValue2 = basePrice * quantity * discount;        return tempValue1 + tempValue2;    }        public double factor() {        return 0.99;    }} //上面的程序也许不适合做一个例子,请先不管它的逻辑是什么//构建一个新类class Calculator {    private final Account account;    private int basePrice;    private double discount;    private int quantity;    private int tempValue1;    private int tempValue2;        public Calculator(Account account, int basePrice, double discount, int quantity) {        this.account = account;        this.basePrice = basePrice;        this.discount = discount;        this.quantity = quantity;    }}//接下来,修改Account的旧函数,将它的工作委托给刚完成的这个函数对象public class Account {    public int calculate(int basePrice, double discount, int quantity) {        return new Calculator(this, basePrice, discount, quantity);    }        public double factor() {        return 0.99;    }} //于是乎,Calculator的函数就可以这么设计了class Calculator {    private final Account account;    private int basePrice;    private double discount;    private int quantity;    private int tempValue1;    private int tempValue2;        public Calculator(Account account, int basePrice, double discount, int quantity) {        this.account = account;        this.basePrice = basePrice;        this.discount = discount;        this.quantity = quantity;    }    public int calculator() {        this.tempValue1 = basePrice * quantity + account.factor();        this.tempValue2 = basePrice * quantity * discount;        return tempValue1 + tempValue2;    }}//如果Calculator的calculate函数需要再一次重构,就可以在Calculator中进行重构了

Substitude Algorithm(替换算法)

你想把某个算法替换为另一个更清晰的算法。

那么就直接把函数体替换为另一个算法吧

String foundPerson(String[] persons) {    for (int i = 0; i < persons.length; i++) {        if (persons[i].equals("Don")) {return "Don";        }        if (persons[i].equals("John")) {return "John";        }        if (persons[i].equals("Kent")) {return "Kent";        }    }}//对算法进行重构String foundPerson(String[] persons) {    List candidates = Arrays.asList(new String[]{"Don", "John", "Kent"});    for (int i = 0; i < persons.length; i++) {        if (candidates.contains(persons[i])) {return persons[i];        }    }}

在进行算法重构之前,需要先确定自己已经充分了解原来的算法。

热点阅读

网友最爱