阅读(3057) (8)

Extract重构

2018-10-18 10:30:05 更新

Extract重构

IntelliJ IDEA提供各种Extract重构,以引入参数,变量,常量,字段,方法和函数。要运行任何这些重构,请选择要重构的表达式并选择:Refactor|提取|<target>。您可以选择整个表达式或将光标放在其中的任何位置,IntelliJ IDEA将帮助您进行选择。

Extract Parameter

使用Extract Parameter(提取参数)重构将函数调用中的表达式替换为参数。IntelliJ IDEA将相应地更新声明和函数调用。新参数的默认值可以在函数体内初始化或通过函数调用传递。

假设您在函数calculate_sum(i)中有一段硬编码1的代码。使用Extract Parameter重构,您可以使用i2参数替换此硬编码1。新i2参数可以作为可选项或根据需要提取。

示例1:提取可选参数

提取新参数i2作为可选参数。新参数在主体calculate_sum(i)中初始化,并且show_sum()中calculate_sum(i)调用不会更改。

function calculate_sum(i) {
    alert('Adding ' + 1 + ' to ' + i);
    return  1 + i;
}

function show_sum() {
    alert('Result: ' + calculate_sum(5));
}
function calculate_sum(i, i2) {
    i2 = i2 || 1;
    alert('Adding ' + i2 + ' to ' + i);
    return i2 + i;
}

function show_sum() {
    alert('Result: ' + calculate_sum(5));
}

示例2:提取所需参数

提取新参数i2作为必需参数,相应地更改show_sum()中calculate_sum(i)调用。

function calculate_sum(i) {
    alert('Adding ' + 1 + ' to ' + i);
    return 1 + i;
}

function show_sum() {
    alert('Result: ' + calculate_sum(5));
}
function calculate_sum(i, i2) {
    alert('Adding ' + i2 + ' to ' + i);
    return i2 + i;
}

function show_sum() {
    alert('Result: ' + calculate_sum(5, 1));
}

提取参数的操作如下:

  1. 在编辑器中,将光标放在要转换为参数的表达式中,然后按Ctrl+Alt+P,或在上下文菜单或主菜单上选择:Refactor|提取|参数。
  2. 如果在当前光标位置中检测到多个表达式,请在“表达式”列表中选择所需的表达式。
    ws_js_extract_parameter_select_expression.png
  3. 如果找到多个选定表达式,请选择“仅替换此事件”或“找到多个匹配项”弹出菜单中的“替换所有匹配项”。
    ws_js_extract_parameter_multiple_occurrences.png
    最后,出现用于配置重构的弹出窗口。
    ws_js_extract_parameter_specify_parameter_name_and_type.png
  4. 选择Generate JSDoc以生成JSDoc注释块。如果您需要指定自定义默认参数值,这可能会有所帮助。从JSDoc官方网站了解更多信息。
  5. 选择新参数的类型(可选或必需)并指定其默认值(如果适用):
    • 如果选中“可选参数”复选框,则将使用函数体中的默认值初始化该参数。
    • 如果清除“可选参数”复选框,则默认参数值将通过现有函数调用传递。所有函数调用都将根据新的函数签名进行更改,并且参数初始化将添加到函数体中。
    最初,IntelliJ IDEA接受调用重构作为默认值的表达式。在大多数情况下,您无需更改它。如果仍然需要,请以格式@param <parameter name> - <default value>在JSDoc注释中指定另一个默认值。
  6. 通过在弹出列表中双击建议的参数名称,或者在文本框中使用红色画布指定自定义名称,接受其中一个建议的参数名称。准备好后按“Enter”。
    ws_js_extract_parameter_result.png
    另请注意,在ES6代码中,将应用新的默认函数参数语法function calculate_sum(i, i2 = 1) 而不是i2 = i2 || 1;。从https://developer.mozilla.org网站了解有关默认函数参数的更多信息 。

选择重构模式:

您可以如上所述在编辑器中(在in-place模式下)提取参数, 或使用“提取参数(Extract Parameter )”对话框。这两种方法相似,区别如下:

  • 预览重构的结果。在对话框中,可以单击“预览”并在“查找”工具窗口的专用选项卡中检查预期的更改。在in-place模式下,此功能不可用。
  • 指定默认参数值。在对话框中,IntelliJ IDEA会在“值”字段中建议默认参数值,您可以在其中接受建议或指定其他值。在in-place模式下,IntelliJ IDEA将调用重构的表达式视为默认参数值。要指定另一个值,您必须使用JSDoc注释块。

默认情况下,IntelliJ IDEA在in-place模式下运行Extract Parameter重构。要使用“提取参数”对话框,请在“设置/首选项”对话框(Ctrl+Alt+S)中单击:编辑器|常规。在打开的“常规”页面上,清除“重构”区域中的“启用in-place模式”复选框。

Extract Variable

使用Extract Variable(提取变量)重构将表达式替换为函数范围的变量(var),块范围的变量(let)或常量。这种重构使您的源代码更易于阅读和维护。它还可以帮助您避免使用硬编码常量,而无需对其值或目的进行任何解释。

假设您在return语句中有一个带有部分硬编码表达式的函数:

Parenizor.method('toString', function ()) {
    return '(' + this.getValue() + ')';
}

使用Extract Variable重构,您可以使用变量替换'(' + this.getValue() + ')'表达式,例如string。提取变量的范围取决于其声明(var或let)中使用的语句以及声明新变量的上下文(函数内部或外部)。

示例1:使用let语句声明提取块范围的变量

从return语句中的'(' + this.getValue() + ')'表达式中提取变量。新变量使用let语句在Parenizor.method('toString', function ())内部声明。 


Parenizor.method('toString', function ()) {
    return '(' + this.getValue() + ')';
}


Parenizor.method('toString', function ()) {
    let string = '(' + this.getValue() + ')';
    return string;
}

示例2:提取变量并在任何函数外声明它

变量appName从navigator.appName表达式中提取并在任何函数之外使用var语句声明。


var browserName = "N/A";
if (navigator.appName.indexOf("Netscape") != -1) {
    browserName = "NS";
} else if (navigator.appName.indexOf("Microsoft") != -1) {
    browserName = "MSIE";
} else if (navigator.appName.indexOf("Opera") != -1) {
    browserName = "O";
}


var browserName = "N/A";
var appName = navigator.appName;
if (appName.indexOf("Netscape") != -1) {
    browserName = "NS";
} else if (appName.indexOf("Microsoft") != -1) {
    browserName = "MSIE";
} else if (appName.indexOf("Opera") != -1) {
    browserName = "O";
}

提取变量的操作如下所示:

  1. 在编辑器中,选择要转换为变量的表达式,然后按Ctrl+Alt+V,或在上下文菜单或主菜单上选择:Refactor |提取|变量。
  2. 如果在当前光标位置中检测到多个表达式,请在“表达式”列表中选择所需的表达式。
    ws_js_refactoring_extract_variable_inplace_select_expression.png
  3. 如果找到多个选定表达式,请选择“仅替换此事件”或“找到多个匹配项”弹出菜单中的“替换所有匹配项”。
    ws_js_refactoring_extract_variable_inplace_multiple_occurrences.png
    最后,出现用于配置重构的弹出窗口。
  4. 在弹出菜单中,选择要在新变量声明中使用的语句:
    • 选择var以引入函数范围的变量。
    • 选择let以引入块范围的变量,请参阅上面的示例2。
    • 选择const来引入常量。
    ws_js_refactoring_extract_variable_inplace_choose_scope_type.png
  5. 通过在弹出列表中双击建议的变量名称或在文本框中指定自定义名称来接受其中一个建议变量名称。准备好后按“Enter”。

选择重构模式

您可以如上所述在编辑器中(在in-place模式下)提取变量, 或使用“提取变量”对话框。默认情况下,IntelliJ IDEA在in-place模式下运行Extract Variable重构。要使用“提取变量”对话框,请在“设置/首选项”对话框(Ctrl+Alt+S)中单击:编辑器|常规。在打开的“常规”页面上,清除“重构”区域中的“启用in-place模式”复选框。

Extract Field

在Extract Field重构宣布一个新的字段,并使用选定的表达对其进行初始化。原始表达式将替换为字段的用法。

在下面的示例中,提取相同的_calcArea字段。这些示例说明了初始化提取字段的三种不同方法。

示例1:在封闭方法中初始化提取的字段


class Rectangle {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }

    get area() {
        return this.calcArea();
    }

    calcArea() {
        return this.height * this.width;
    }
}


class Rectangle {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }

    _calcArea;

    get area() {
        this._calcArea = this.calcArea();
        return this._calcArea;
    }

    calcArea() {
        return this.height * this.width;
    }
}

示例2:提取的字段在其声明中初始化


class Rectangle {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }

    get area() {
        return this.calcArea();
    }

    calcArea() {
        return this.height * this.width;
    }
}


class Rectangle {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }

    _calcArea = this.calcArea();

    get area() {
        return this._calcArea;
    }

    calcArea() {
        return this.height * this.width;
    }
}

示例3:提取的字段在类的构造函数中初始化


class Rectangle {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }

    get area() {
        return this.calcArea();
    }

    calcArea() {
        return this.height * this.width;
    }
}


class Rectangle {
    constructor(height, width) {
        this._calcArea = this.calcArea();
        this.height = height;
        this.width = width;
    }

    _calcArea;

    get area() {
        return this._calcArea;
    }

    calcArea() {
        return this.height * this.width;
    }
}

提取字段的操作如下:

  1. 在编辑器中,选择要转换为字段的表达式,然后按Ctrl+Alt+F,或从上下文菜单或主菜单上选择:Refactor|提取|字段。“提取字段”对话框将打开。
  2. 从列表中接受一个建议的名称或键入自定义名称。
  3. 选择新字段的初始化位置:
    • 目前的方法,见上面的例1。
    • 字段声明,请参见上面的示例2。
    • 类构造函数,请参见上面的示例3。
    ws_js_extract_field_dialog_1.png

Extract Method

该Extract Method重构,您可以使用提取的代码创建命名方法或函数。当调用Extract Method重构时,IntelliJ IDEA会检测作为所选代码片段输入的变量以及作为其输出的变量。检测到的输出变量用作提取的方法或函数的返回值。

在下面的示例中,从c = a + b;表达式中提取函数。

实例1:从另一个函数内的表达式提取一个全局范围函数

调用重构的c = a + b;表达式,位于MyFunction()函数内部。选择全球目标范围。

例1.1:生成函数声明


function MyFunction(a,b) {
    c = a + b;
    return (c * c);
}
result = MyFunction(4,6);
document.write(result);


function extracted(a, b) {
    c = a + b;
}

function MyFunction(a,b) {
    extracted(a, b);
    return (c * c);
}
result = MyFunction(4,6);
document.write(result);

例1.2:提取的函数在表达式中声明


function MyFunction(a,b) {
    c = a + b;
    return (c * c);
}
result = MyFunction(4,6);
document.write(result);


let extracted = function (a, b) {
    c = a + b;
};

function MyFunction(a,b) {
    extracted(a, b);
    return (c * c);
}
result = MyFunction(4,6);
document.write(result);

实例2:从任何函数之外的表达式提取一个全局范围函数

调用重构的c = a + b;表达式,位于任何函数之外。因此,无法选择目标范围。

例2.1:生成函数声明


c = a + b;


function extracted() {
    c = a + b;
}

extracted();

例2.2:提取的函数在表达式中声明


c = a + b;


let extracted = function () {
    c = a + b;
};
extracted();

示例3:在封闭函数内提取具有定义的函数

调用重构的c = a + b;表达式,位于MyFunction()函数内部。选择函数MyFunction目标范围。


function MyFunction(a,b) {
    c = a + b;
    return (c * c);
}
result = MyFunction(4,6);
document.write(result);


function MyFunction(a,b) {
    function extracted() {
        c = a + b;
    }

    extracted();
    return (c * c);
}
result = MyFunction(4,6);
document.write(result);

提取函数的操作如下:

  1. 在编辑器中,选择要转换为函数的代码片段,然后按Ctrl+Alt+M,或从上下文菜单或主菜单上选择:Refactor|提取|方法。
  2. 如果所选表达式位于函数内,请从弹出列表中选择目标范围:
    • 如果选择全局,则提取的函数将在任何函数外声明。参见上面的示例1。
    • 要在当前封闭函数内定义提取的函数,请选择function <current enclosing function name>。参见上面的实施例3。
      a685a45a-2bf8-46cb-85ee-63e7b26ff646
  3. 要打开包含更多选项的“提取函数”对话框,请再按一次Ctrl+Alt+M。在此对话框中,您可以选择是通过生成的函数声明还是在表达式内声明提取的函数 。见上面的例子。
    30f852de-4c11-4acf-a47b-6dae6a0e0017

如何在默认情况下打开“Extract Function”对话框:

  • 在“设置/首选项”对话框(Ctrl+Alt+S)中,单击:编辑器|常规。在打开的“常规”页面上,清除“重构”区域中的“启用in-place模式”复选框。

Extract Superclass

该Extract Superclass(提取超类)重构创建基于当前类的成员一个新的抽象类。创建的类会自动扩展。

假设您有一个类AccountingDepartment,并且您希望来自它的printName()方法能够重新使用。

class AccountingDepartment {
    name;

    printName() {
        console.log("Department name: " + this.name);
    }

    printMeeting() {
        console.log("The Accounting Department meets each Monday at 10am.");
    }

    generateReports() {
        console.log("Generating accounting reports...");
    }
}

您可以提取超类Department并在其中包含printName该Name字段。

class Department {
    name;

    printName() {
        console.log("Department name: " + this.name);
    }
}

class AccountingDepartment extends Department {
    printMeeting() {
        console.log("The Accounting Department meets each Monday at 10am.");
    }

    generateReports() {
        console.log("Generating accounting reports...");
    }
}

提取超类的操作如下:

  1. 将光标放在要从中提取超类的类的任何位置。
  2. 在主菜单或上下文菜单上选择:Refactor|提取|超类。“提取超类”对话框将打开。
  3. 指定新超类的名称,然后选择要包含在其中的类成员旁边的复选框。(可选)标记要进行抽象的成员。
  4. 在“目标文件”字段中,指定新类所在文件的位置。默认情况下,该字段显示调用重构的当前文件的路径。
  5. 选择Extract Superclass。IntelliJ IDEA创建一个新类并使用extends标记源类。
    要创建超类并使用对方法参数中超类的引用替换对源类的引用,请选择Extract superclass并尽可能使用它。IntelliJ IDEA在“查找”工具窗口的“重构预览”窗格中显示建议的更改。

Extract Vue Component

Extract Vue Component(提取Vue组件)重构允许您从现有组件中提取新的Vue.js组件,而无需任何复制和粘贴。请注意,此重构仅适用于in-place模式,因此请确保在“编辑器:常规”页面上选中“启用in-place模式”复选框 。

提取Vue组件的操作方法如下:

  1. 选择要提取的模板片段,然后在主菜单或选择的上下文菜单中选择:Refactor|提取|提取Vue组件。
  2. 输入新组件的名称。如果此名称已被使用或无效,则IntelliJ IDEA会显示警告。否则,将创建一个新的单文件组件并将其导入父组件。