《重构-改善既有代码的设计》- 重新组织函数

所谓的重构就是在不改变代码外部行为(功能)的情况下对代码进行内部修改以实现代码可读性、可维护性、可复用性以及可扩展性的大幅度增加,便于后续进行扩展和维护(直观提高代码可读性,利于定位Bug并加以修复)。

避免出现 “too-long" 方法,要求方法表现的逻辑简洁明了(concise and easy to understand)。

🍎【Extract Method】- 提炼方法

将代码放入一个独立方法中,并让方法的名称具有自我描述性

特点:

  1. 功能模块化
  2. 模块集成化
  3. 局部变量局部化
  4. 初始变量分离化

处理对象:

  1. 过长方法
  2. 方法包含的代码逻辑复杂混乱,直观性差。

实现目标:
降低方法粒度,提高方法复用性,让高层函数读起来像是(just like)读注释一样。

方法粒度小便于后续的复写、复用和扩展

class Order {
    private double price;

    public Order(double price){
        this.price = price;
    }
    double getAmount(){
        return this.price;
    }
}

public class Sample01 {

    private Vector<Order> _orders;
    private String _name;
    public Sample01(String name){
        this._name = name;
    }
   //【高层函数】遵守"单一指责型"这个原则,实现模块(方法)功能独立
    void printOwing(){
        printBanner(); // print banner
        double outstanding = getOutstanding(); // calculate outstanding
        printDetails(_name,outstanding); // print details
    }

    // calculate outstanding 【局部变量局部化】
    private double getOutstanding() {
        Enumeration e =  _orders.elements();
        double result = 0.0;
        while(e.hasMoreElements()){
            Order order = (Order)e.nextElement();
            result += order.getAmount();
        }
        return result;
    }

    // print details
    private void printDetails(String username, Double outstanding) {
        System.out.println("username: " + username);
        System.out.println("amount: " + outstanding);
    }

    // print banner
    private void printBanner() {
        System.out.println("*************************");
        System.out.println("***** Customer Owes *****");
        System.out.println("*************************");
    }

}

/**
 * the characteristic of Extract Method
 * 1. 局部变量局部化
 * 2. 初始变量分离化
 * 3. 功能模块化
 * 4. 模块集成化
 * */

🍎【Inline Method】- 内联方法

在函数调用点插入函数本体,然后移除函数

处理对象: 代码之间太多的间接层(间接层有价值但不是所有的间接层都有价值)

🍎【Inline Temp】- 内联临时变量

将所有对该变量的引用动作,替换为对它赋值的表达式本身

处理对象:减少临时变量的出现,只用通过内联表达式来达到临时变量的作用(内联临时变量要用于所替代临时变量只会被使用一次的情况下)

🍎【Replace Temp With Query】- 以查询取代临时变量

将这个表达式提炼到一个独立函数中。将这个临时变量的所有引用点替换为对新函数调用
特点:

  1. 模块功能化
  2. 功能集成化

处理对象: 减少长函数的出现

确保提炼出来的函数无任何副作用,该函数并不修改任何对象内容。
运用此方法可能会存在性能方面的考虑,但如果性能真的出现问题可以在优化阶段解决。代码组织良好更有助于发现有效的优化方案

🍎【Introduce Explaining Variable】- 引入解释型变量

将该复杂表达式(或其中一部分)的结果放进一个临时比那辆,以此变量名称来解释表达式用途

处理好处: 通过自我描述性的变量代替冗杂、逻辑不清的表达式以提高代码可读性(concise and easy to understand)

public class Sample05 {
    private double _quantity;
    private double _itemPrice;
    
    // *************** initial version 1.0.0 ***************
    double calculatePrice01(){
        // price is base_price - quantity_discount + shipping
        return _quantity * _itemPrice -
                Math.max(0, _quantity - 500) * _itemPrice * 0.05 +
                Math.min(_quantity * _itemPrice * 0.1, 100.0);

    }
    // *************** 【Introduce Explaining Variables】initial version 1.0.1 ***************
    double calculatePrice02(){
        // price is base_price - quantity_discount + shipping
        final double basePrice = _quantity * _itemPrice;
        return basePrice -
                Math.max(0, _quantity - 500) * _itemPrice * 0.05 +
                Math.min(basePrice * 0.1, 100.0);
    }

    // *************** 【Introduce Explaining Variables】initial version 1.0.2 ***************
    double calculatePrice03(){
        // price is base price - quantity discount + shipping
        final double basePrice = _quantity * _itemPrice;
        final double quantityDiscount = Math.max(0, _quantity - 500) * _itemPrice * 0.05;
        final double shipping = Math.min(basePrice * 0.1, 100.0);
        return basePrice - quantityDiscount + shipping;
    }


    // *************** 【Extract Method】initial version 1.0.3 ***************
    double calculatePrice04(){
        return basePrice() - quantityDiscount() + shipping();
    }

    private double basePrice(){
        return _quantity * _itemPrice;
    }

    private double quantityDiscount(){
        return Math.max(0, _quantity - 500) * _itemPrice * 0.05;
    }

    private double shipping(){
        return Math.min(basePrice() * 0.1, 100.0);
    }
    // Concise and easy to understand
}

🍎【Remove Assignments to Parameters】- 移除对参数的赋值

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

public class Sample07 {
    // ****************【Remove Assignments To Parameters】version 1.0.0 ****************
    int discount01(int inputVal, int quantity, int yearToDate){
        if(inputVal > 50){
            inputVal -= 2;
        }
        if(quantity > 100){
            inputVal -= 1;
        }
        if(yearToDate > 10000){
            inputVal -= 4;
        }
        return inputVal;
    }
    // ****************【Remove Assignments To Parameters】version 1.0.1 ****************
    int discount02(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;
    }

    // ****************【Remove Assignments To Parameters】version 1.0.2 ****************
    int discount03(final int inputVal, final int quantity, final int yearToDate){ // final: 1. 保证变量一致性 2. 防止出现参数再次赋值
        int result = inputVal;
        if(inputVal > 50){
            result -= 2;
        }
        if(quantity > 100){
            result -= 1;
        }
        if(yearToDate > 10000){
            result -= 4;
        }
        return result;
    }
    // To implement compulsory no-assignment to parameter with the "final" keyword.(the "final" better use in too long method)
}

🍎【Split Temporary Variable】- 分解临时变量

针对每次赋值,创建一个独立、对应的临时变量(临时变量的唯一化和遵守单一职责的原则)

🍎【Replace Method With Method Object】- 以函数对象取代函数

将这个方法放进一个单独对象中,如此一来局部变量就成了对象内的字段。然后可以在同一个对象中将这个大型方法分解为多个小型方法。

处理对象: 无法拆解的方法
处理好处:将相对独立的代码从大型函数中提炼处理啊,就可以大大提高代码的可读性。

class Account{
    private int inputVal;
    private int quantity;
    private int yearToDate;

    // traditional Method
    int gamma01(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;
    }

    int gamma02(int inputVal, int quantity, int yearToDate){  【⭐️Nice Shot】
        return new Gamma(this,inputVal,quantity,yearToDate).compute();
    }


    int delta(){
        return 1;
    }
}

// Method Object
class Gamma{
    private final Account _account; // The _account field must be used anywhere in a function that calls the Account class
    private int inputVal;
    private int quantity;
    private int yearToDate;
//   【extract method】
//    private int importantValue1;
//    private int importantValue2;
//    private int importantValue3;

    Gamma(Account source, int inputValArg, int quantityArg, int yearToDateArg){
        this._account = source;
        this.inputVal = inputValArg;
        this.quantity = quantityArg;
        this.yearToDate = yearToDateArg;
    }
     // refactoring method
    int compute(){  
        if((yearToDate - importantValue1()) > 100){
            return getImportantValue3(importantValue2() - 20) - 2 * importantValue1();
        }
        return getImportantValue3(importantValue2()) - 2 * importantValue1();
    }

    int importantValue1(){
        return (inputVal * quantity) + _account.delta();
    }

    int importantValue2(){
        return (inputVal * yearToDate) + 100;
    }

    int getImportantValue3(int val){
        return val * 7;
    }
}

🍎【Substitute Algorithm】- 替换算法

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

"重构"充分发挥Divide and Conquer的思想,将复杂的东西分解为小块。

posted @ 2021-02-01 16:07  Felix_Openmind  阅读(175)  评论(0)    收藏  举报
*{cursor: url(https://files-cdn.cnblogs.com/files/morango/fish-cursor.ico),auto;}