再读经典重构、重构与模式、修改代码的艺术《三》

重新组织你的函数

Extract Method

将一段代码放进一个独立函数中,并让函数名称解释该函数的用途。

void printOwing (double amount) {
    printBanner();

    //print details
    System.out.println("name:" + _name);
    System.out.println("amount:" + amount);
}
void printOwing (double amount) {
    printBanner();
    printDetails(amount);
}

void printDetails(double amount) {
    System.out.println("name:" + _name);
    System.out.println("amount:" + amount);
}

动机

Extract Method是最常用的重构手法之一。当看见一个过长的函数或者一段需要注释才能让人理解用途的代码,就可以将这段代码放进一个独立函数中。

作法

  • 创造一个新函数,根据这个函数的意图来给它命名(以它做什么来命名,而不是以怎样做命名)
  • 将提炼出的代码从源函数拷贝到新建的目标函数中
  • 仔细检查提炼出的代码,看看其中是否引用了作用域限于源函数的变量(包括局部变量和源函数参数)
  • 检查是否有仅用于被提炼码的临时变量。如果有,在目标函数中将它们声明为临时变量
  • 检查被提炼码,看看是否有任何局部变量的值被它改变。如果一个临时变量值被修改了,看看是否可以将被提炼码处理为一个查询,并将结果赋值给相关变量。如果很难这样做,或如果被修改的变量不止一个,你就不能仅仅将这段代码原封不动地提炼出来。你可能需要先使用Split Temporary Variable,然后再尝试提炼。也可以使用Replace Temp with Query将临时变量消灭掉
  • 将被提炼码中需要读取的局部变量,当作参数传给目标函数
  • 处理完所有局部变量之后,进行编译
  • 在源函数中,将被提炼码替换为对目标函数的调用
  • 编译,测试

范例:无局部变量

void printOwing() {
    Enumeration e = _orders.elements(); 
    double outstanding = 0.0;

    //print banner
    System.out.println ("**************************"); 
    System.out.println ("***** Customer Owes ******"); 
    System.out.println ("**************************");

    //calculate outstanding 
    while (e.hasMoreElements()) {
        Order each = (Order) e.nextElement();
        outstanding += each.getAmount(); 
    }

    //print details
    System.out.println ("name:" + _name); 
    System.out.println ("amount" + outstanding);
}
void printOwing() {
    Enumeration e = _orders.elements(); 
    double outstanding = 0.0;
    printBanner();

    // calculate outstanding 
    while (e.hasMoreElements()) {
        Order each = (Order) e.nextElement();
        outstanding += each.getAmount(); 
    }

    //print details
    System.out.println ("name:" + _name); 
    System.out.println ("amount" + outstanding);
}

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

范例:有局部变量

void printOwing() {
    Enumeration e = _orders.elements(); 
    double outstanding = 0.0;

    printBanner();

    // calculate outstanding 
    while (e.hasMoreElements()) {
        Order each = (Order) e.nextElement();
        outstanding += each.getAmount(); 
    }

    //print details
    System.out.println ("name:" + _name); 
    System.out.println ("amount" + outstanding);
}
void printOwing() {
    Enumeration e = _orders.elements(); 
    double outstanding = 0.0;
    printBanner();

    // calculate outstanding 
    while (e.hasMoreElements()) {
        Order each = (Order) e.nextElement();
        outstanding += each.getAmount(); 
    }

    printDetails(outstanding);
}

void printDetails (double outstanding) { 
    System.out.println ("name:" + _name); 
    System.out.println ("amount" + outstanding);
}

范例:对局部变量再赋值

被赋值的临时变量分两种情况。

  • 较简单的情况是:这个变量只在被提炼码区段中使用。如果是,你可以将这个临时变量的声明式移到被提炼码中,然后一起提炼出去。
  • 另一种情况是:被提炼码之外也使用了这个变量。这又分两种情况:如果这个变量在被提炼码之后未再被使用,你只需直接在目标函数中修改它就可以了;如果被提炼码之后的代码还使用了这个变量,你就需要让目标函数返回该变量改变后的值。
void printOwing() {
    Enumeration e = _orders.elements(); 
    double outstanding = 0.0;

    printBanner();

    // calculate outstanding 
    while (e.hasMoreElements()) {
        Order each = (Order) e.nextElement();
        outstanding += each.getAmount(); 
    }

    printDetails(outstanding); 
}
void printOwing() { 
    printBanner();
    double outstanding = getOutstanding();
    printDetails(outstanding); 
}

double getOutstanding() {
    Enumeration e = _orders.elements(); 
    double outstanding = 0.0;

    while (e.hasMoreElements()) {
        Order each = (Order) e.nextElement();
        outstanding += each.getAmount(); 
    }

    return outstanding; 
}
double getOutstanding() {
    Enumeration e = _orders.elements(); 
    double result = 0.0;

    while (e.hasMoreElements()) {
        Order each = (Order) e.nextElement();
        result = each.getAmount(); 
    }

    return result; 
}

另外一种情况:

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); 
}
void printOwing(double previousAmount) { 
    double outstanding = previousAmount * 1.2; 
    printBanner();

    outstanding = getOutstanding(outstanding); 

    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; 
}
void printOwing(double previousAmount) { 
    printBanner();
    double outstanding = getOutstanding(previousAmount * 1.2);
    printDetails(outstanding); 
}
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页