重构-基础4(重构方法之重新组织函数)

重构方法

临时变量只能在函数内使用,会使函数变得很长,所以尽可能少的使用临时变量。

一、内联临时变量

把对临时变量的引用,改成得到临时变量的表达式本身。
修改前:

    private static Double calculateMoney(Integer num, Double price) {
        return num * price;
    }

    public static void main(String[] args) {
        Double moneySum = calculateMoney(10, 20.05);
        if (moneySum > 100) {
            System.out.println("买不起");
        } else {
            System.out.println("买得起");
        }
    }

修改后:

    private static Double calculateMoney(Integer num, Double price) {
        return num * price;
    }

    public static void main(String[] args) {
        if (calculateMoney(10, 20.05) > 100) {
            System.out.println("买不起");
        } else {
            System.out.println("买得起");
        }
    }

二、以查询取代临时变量

把临时变量的表达式提取到新函数,然后调用处直接用新函数就好~
修改前:

public static Double getPrice(Integer quantity, Integer itemPrice) {
        int basePrice = quantity * itemPrice;
        double discountFactor;
        if (basePrice > 1000) {
            discountFactor = 0.95;
        } else {
            discountFactor = 0.98;
        }
        return basePrice * discountFactor;
    }

    public static void main(String[] args) {
        System.out.println("价格:"+getPrice(10,20));
    }

修改后:

    private static Integer getBasePrice(Integer quantity, Integer itemPrice) {
        return quantity * itemPrice;
    }
    private static double getDiscountFactor(Integer quantity, Integer itemPrice) {
        if (getBasePrice(quantity,itemPrice) > 1000) {
            return 0.95;
        } else {
            return 0.98;
        }
    }

    public static Double getPrice(Integer quantity, Integer itemPrice) {
        return getBasePrice(quantity,itemPrice) * getDiscountFactor(quantity,itemPrice);
    }

    public static void main(String[] args) {
        System.out.println("价格:"+getPrice(10,20));
    }

三、引入解释性变量

将复杂表达式拆分,放入临时变量里,变量名称用来解释表达式用途。

    // quantity:数量 itemPrice:单价
    // 计算逻辑 价格 = 单价*数量 - 折扣 + 运费
    // 折扣的计算逻辑:数量小于500,不打折,数量超过500的部分,打95折
    // 运费的计算逻辑:单价*数量*0.1,但是超过100的,付100就好
    private static double getPrice(Integer quantity, Integer itemPrice) {
        return quantity * itemPrice -
                Math.max(0, quantity - 500) * itemPrice * 0.05 +
                Math.min(quantity * itemPrice * 0.1, 100);
    }

    public static void main(String[] args) {
        System.out.println("价格:" + getPrice(10, 20));
    }

可以看出,该函数虽然短,但是很难理解,这时候,可以把复杂的逻辑拆成临时变量,提高可读性。
修改后:

   private static double getPrice(Integer quantity, double itemPrice) {
        double basePrice = quantity * itemPrice;
        double discount = Math.max(0, quantity - 500) * itemPrice * 0.05;
        double shipping = Math.min(basePrice * 0.1, 100);
        
        return basePrice - discount + shipping;
    }

    public static void main(String[] args) {
        System.out.println("价格:" + getPrice(10, 20.05));
    }

可以看出,产生了好多临时变量,继续优化如下:

    private static double getBasePrice(Integer quantity, double itemPrice) {
        return quantity * itemPrice;
    }

    private static double getDiscount(Integer quantity, double itemPrice) {
        return Math.max(0, quantity - 500) * itemPrice * 0.05;
    }

    private static double getShipping(Integer quantity, double itemPrice) {
        return Math.min(getBasePrice(quantity, itemPrice) * 0.1, 100);
    }

    private static double getPrice(Integer quantity, double itemPrice) {
        return getBasePrice(quantity,itemPrice) - getDiscount(quantity,itemPrice) + getShipping(quantity,itemPrice);
    }

    public static void main(String[] args) {
        System.out.println("价格:" + getPrice(10, 20.05));
    }

四、分解临时变量

临时变量被赋值多次,且之间毫无关系(循环变量和结果收集变量是有关系的),那么就拆成多个不同的临时变量。

   private static void getResult(Integer quantity, double itemPrice) {
        double result = quantity * itemPrice;
        if (result > 10) {
            result = quantity / 2 * itemPrice;
            if (result > 10) {
                System.out.println("少买一半,还是买不起");
            } else {
                System.out.println("少买一半,终于买得起");
            }
        } else {
            System.out.println("有钱 买得起");
        }
    }

    public static void main(String[] args) {
        getResult(2,6);
    }
       

可以看出,想直接消除result变量,比较复杂(emmm,假装很复杂吧),两个result之间并没有什么关系,先把它拆开吧。

    private static void getResult(Integer quantity, double itemPrice) {
        double originalPrice = quantity * itemPrice;
        if (originalPrice > 10) {
            double laterPrice = quantity / 2 * itemPrice;

            if (laterPrice > 10) {
                System.out.println("少买一半,还是买不起");
            } else {
                System.out.println("少买一半,终于买得起");
            }
        } else {
            System.out.println("有钱 买得起");
        }
    }

    public static void main(String[] args) {
        getResult(2,6);
    }

接着对临时变量进行优化

    private static double getOriginalPrice(Integer quantity, double itemPrice) {
        return quantity * itemPrice;
    }
    private static double getLaterPrice(Integer quantity, double itemPrice) {
        return quantity / 2 * itemPrice;
    }
    
    private static void getResult(Integer quantity, double itemPrice) {
        if (getOriginalPrice(quantity, itemPrice) > 10) {
            if (getLaterPrice(quantity, itemPrice) > 10) {
                System.out.println("少买一半,还是买不起");
            } else {
                System.out.println("少买一半,终于买得起");
            }
        } else {
            System.out.println("有钱 买得起");
        }
    }

    public static void main(String[] args) {
        getResult(2,6);
    }

五、移除对参数的赋值

如果对参数进行修改重新赋值,是不合理的,尽量避免这种情况,因为JAVA内总是使用值传递的方式,方法体内的重新赋值并不会对调用方造成任何变化,如下:

    public static void main(String[] args) {
        Date d1 = new Date();
        System.out.println(d1);
        nextDate(d1);
        System.out.println("(调用nextDate结果)date + 1 : " + d1);

        Date d2 = new Date();
        nextDate2(d2);
        System.out.println("(调用nextDate2结果)date + 1 : " + d2);
    }

    private static void nextDate(Date date) {
        date.setDate(date.getDate() + 1);
        System.out.println("(nextDate)date + 1 : " + date);
    }

    private static void nextDate2(Date date) {
        date = new Date(date.getYear(),date.getMonth(),date.getDate() + 1);
        System.out.println("(nextDate2)date + 1 : " + date);
    }

结果如下:
打印结果
显然,对于参数date对象,对它进行修改是可以修改的(d1的前后值一致),
但是在调用函数里,对它重新赋值是不可以的,(d2前后值并不一致);

具体的修改方式如下:
修改前:

private int discount(int inputval, int quantity, int yearToDate) {
        if (inputval > 50) inputval -= 2;
        if (quantity > 100) inputval -= 1;
        if (yearToDate > 10000) inputval -= 4;
        return inputval;
    }

修改后:

 private int discount(int inputval, int quantity, int yearToDate) {
        int result = inputval;
        if (inputval > 50) result -= 2;
        if (quantity > 100) result -= 1;
        if (yearToDate > 10000) result -= 4;
        return result;
    }

参数只用来传递值,不要用来修改值啦~

六、以函数对象取代函数

如果有一个大型函数,里面的局部变量过多并且使用复杂,那么可以把这个函数放在一个单独的对象里,然后把局部变量变成对象内的字段,将这个大型函数分割成小型函数。
修改前:

public class Cook {

    double deleta() {
        return Math.random();
    }

    private double knownMethods(int inputval, int quantity, int yearToDate) {
        double importantValue1 = (inputval * quantity) + deleta();
        double importantValue2 = (inputval * quantity) + 100;
        if ((yearToDate - importantValue1) > 100) {
            importantValue2 -= 20;
        }
        double importantValue3 = importantValue2 * 7 ;
        return importantValue3 - 2 * importantValue1;
    }
}

由上,出现了很多临时对象,且对象之间存在一定的关系,如果要抽离,其实是蛮复杂的。
所以,直接抽离成一个对象,修改后如下:

public class Known {
    private final Cook cook; // 源类
    private int inputval; // 源方法参数1
    private int quantity; // 源方法参数2
    private int yearToDate; // 源方法参数3

    private double importantValue1;
    private double importantValue2;
    private double importantValue3;

    // 初始化方法,初始源类,以及源方法参数
    Known(Cook cook, int inputval, int quantity, int yearToDate) {
        this.cook = cook;
        this.inputval = inputval;
        this.quantity = quantity;
        this.yearToDate = yearToDate;
    }

    double compute() {
        importantValue1 = (inputval * quantity) + cook.deleta();
        importantValue2 = (inputval * quantity) + 100;
        importantThing();
        importantValue3 = importantValue2 * 7 ;
        return importantValue3 - 2 * importantValue1;
    }
    
    void importantThing() {
        if ((yearToDate - importantValue1) > 100) {
            importantValue2 -= 20;
        }
    }
}


public class Cook {
    double deleta() {
        return Math.random();
    }
    private double knownMethods(int inputval, int quantity, int yearToDate) {
        return new Known(this,inputval,quantity,yearToDate).compute();
    }

如上,把过多的临时变量都写在对象里,当作对象的变量,然后compute函数封装原来的逻辑,简化调用。
步骤:1、新建一个类,类名与其功能相同,变量包含:final 源类、源类方法参数、源类方法临时变量等;
2、类的初始化,将源类,和源类方法参数传递进去,初始化类,
3、创造compute函数,实现源方法逻辑;
4、调用处替换,替换成创造的新类以及调用方法;

七、替换算法

把某一种算法替换成更加清晰的算法
例如:
修改前:

    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 "";
    }

修改后:

private static String foundPerson1(String[] people) {
        List<String> candidates = Arrays.asList(new String[]{"anne", "John", "kent"});
        for (int i = 0; i < people.length; ++i) {
            if (candidates.contains(people[i])) {
                return people[i];
            }
        }
        return "";
    }

寻找更合适,更简单的算法进行替换~

原创文章 88 获赞 21 访问量 3万+

猜你喜欢

转载自blog.csdn.net/cfy1024/article/details/89181704
今日推荐