Eclipseでのリファクタリング

1. 概要

https://refactoring.com/[refactoring.com]で、「リファクタリングは、既存のコード本体を再構築し、外部の動作を変更せずに内部構造を変更するための規律あるテクニック」と読みました。
通常、変数やメソッドの名前を変更したり、デザインパターンを導入してコードをよりオブジェクト指向にしたい場合があります。 最近のIDEには、これらの種類のリファクタリングの目的や他の多くの目的を達成するのに役立つ多くの組み込み機能があります。
このチュートリアルでは、無料の一般的なJava IDEであるEclipseでのリファクタリングに焦点を当てます。
*リファクタリングを開始する前に、リファクタリング中に何も壊れていないことを確認するために、一連のテストを用意することをお勧めします。*

2. 改名

2.1. 変数とメソッドの名前を変更する

*これらの簡単な手順に従って変数とメソッドの名前を変更できます*:
  • **要素を選択

  • 要素を右クリック

  • * [_リファクタリング]> [名前の変更]オプションをクリック*

  • 新しい名前を入力してください

  • _Enter_を押します

    link:/uploads/Eclipse-refactor-1-100x45.png%20100w []
    *ショートカットキー_Alt Shift R_ *を使用して、2番目と3番目の手順を実行することもできます。
    上記のアクションが実行されると、Eclipseはそのファイル内のその要素の使用をすべて見つけ、それらをすべて所定の場所に置き換えます。
    また、高度な機能を使用して、リファクタリングがオンになっているときにアイテムの上にカーソルを移動し、_Options_をクリックすることにより、*他のクラスの参照を更新することができます。
    link:/uploads/Eclipse-refactor-2-100x33.png%20100w []
    これにより、変数またはメソッドの名前を変更し、他のクラスの参照を更新するオプションを持つポップアップが開きます。
    link:/uploads/Eclipse-refactor-3-100x41.png%20100w []

2.2. パッケージの名前変更

パッケージ名を選択し、前の例と同じアクションを実行することにより、パッケージの名前を変更できます。 パッケージの名前を変更できるポップアップがすぐに表示され、参照の更新やサブパッケージの名前変更などのオプションが表示されます。
link:/uploads/Eclipse-refactor-4-100x46.png%20100w []
F2を押して、プロジェクトエクスプローラービューからパッケージの名前を変更することもできます。
link:/uploads/Eclipse-refactor-26-100x52.png%20100w []

2.3. クラスとインターフェースの名前変更

クラスまたはインターフェースの名前を変更するには、同じアクションを使用するか、プロジェクトエクスプローラーで_F2_を押します。 これにより、いくつかの高度なオプションとともに、参照を更新するオプションを含むポップアップが開きます。
link:/uploads/Eclipse-refactor-5-100x56.png%20100w []

3.  抽出

次に、抽出について説明します。 コードの抽出とは、*コードを取得して移動することです*。
たとえば、コードを別のクラス、スーパークラス、またはインターフェイスに抽出できます。 同じクラスの変数またはメソッドにコードを抽出することもできます。
Eclipseは、抽出を実現するさまざまな方法を提供します。これについては、次のセクションで説明します。

3.1. クラスを抽出

コードベースに次の_Car_クラスがあるとします。
public class Car {

    private String licensePlate;
    private String driverName;
    private String driverLicense;

    public String getDetails() {
        return "Car [licensePlate=" + licensePlate + ", driverName=" + driverName
          + ", driverLicense=" + driverLicense + "]";
    }

    // getters and setters
}
ここで、ドライバーの詳細を別のクラスに抽出したいとします。 これを行うには、*クラス内の任意の場所を右クリックし、[_リファクタリング]> [クラスの抽出]オプション*を選択します。
link:/uploads/Eclipse-refactor-6-100x61.png%20100w []
これにより、他のいくつかのオプションとともに、クラスに名前を付けて移動するフィールドを選択できるポップアップが開きます。
link:/uploads/Eclipse-refactor-7-100x71.png%20100w []
*コードをプレビューしてから先に進むこともできます。* _OK_をクリックすると、Eclipseは_Driver_という名前の新しいクラスを作成し、以前のコードは次のようにリファクタリングされます。
public class Car {

    private String licensePlate;

    private Driver driver = new Driver();

    public String getDetails() {
        return "Car [licensePlate=" + licensePlate + ", driverName=" + driver.getDriverName()
          + ", driverLicense=" + driver.getDriverLicense() + "]";
    }

    //getters and setters
}

3.2. 抽出インターフェース

同様の方法でインターフェイスを抽出することもできます。 次の_EmployeeService_クラスがあるとします:
public class EmployeeService {

    public void save(Employee emp) {
    }

    public void delete(Employee emp) {
    }

    public void sendEmail(List<Integer> ids, String message) {
    }
}
*クラス内の任意の場所を右クリックして[_リファクタリング]> [インターフェイスの抽出]オプションを選択するか、または_Alt Shift T_ショートカットキーコマンドを使用してメニューを直接表示することにより、インターフェイスを抽出できます。
link:/uploads/Eclipse-refactor-19-100x63.png%20100w []
これにより、インターフェイス名を入力し、インターフェイスで宣言するメンバーを決定できるポップアップが開きます。
link:/uploads/Eclipse-refactor-8-100x91.png%20100w []
このリファクタリングの結果、インターフェイス_IEmpService_が作成され、_EmployeeService_クラスも変更されます。
public class EmployeeService implements IEmpService {

    @Override
    public void save(Employee emp) {
    }

    @Override
    public void delete(Employee emp) {
    }

    public void sendEmail(List<Integer> ids, String message) {
    }
}

3.3. スーパークラスの抽出

必ずしも従業員の雇用に関するものではないいくつかのプロパティを含む_Employee_クラスがあるとします。
public class Employee {

    private String name;

    private int age;

    private int experienceInMonths;

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public int getExperienceInMonths() {
        return experienceInMonths;
    }
}
非雇用関連のプロパティを_Person_スーパークラスに抽出することもできます。 アイテムをスーパークラスに抽出するには、クラス内の任意の場所を右クリックして[_リファクタリング]> [スーパークラスの抽出]オプションを選択するか、Alt Shift T *を使用してメニューを直接表示します。
link:/uploads/Eclipse-refactor-9-100x69.png%20100w []
これにより、選択した変数とメソッドを使用して新しい_Person_クラスが作成され、_Employee_クラスが次のようにリファクタリングされます。
public class Employee extends Person {

    private int experienceInMonths;

    public int getExperienceInMonths() {
        return experienceInMonths;
    }
}

3.4. 抽出方法

場合によっては、メソッド内の特定のコードを別のメソッドに抽出して、コードをクリーンで維持しやすくすることができます。
たとえば、メソッドにforループが埋め込まれているとします。
public class Test {
    public static void main(String[] args) {
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
    }
}
_Extract Method_ウィザードを呼び出すには、次の手順を実行する必要があります。
  • 抽出するコード行を選択します

  • 選択した領域を右クリックします

  • * _Refactor> Extract Method_オプション*をクリックします

    link:/uploads/Eclipse-refactor-20-100x55.png%20100w []
    *最後の2つのステップは、キーボードショートカット_Alt Shift M_ *でも実行できます。 _Extract Method_ダイアログを見てみましょう:
    link:/uploads/Eclipse-refactor-10-100x92.png%20100w []
    これにより、コードが次のようにリファクタリングされます。
public class Test {

    public static void main(String[] args) {
        printArgs(args);
    }

    private static void printArgs(String[] args) {
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
    }
}

3.5. ローカル変数を抽出する

コードを読みやすくするために、特定の項目をローカル変数として抽出できます。
これは、_String_リテラルがある場合に便利です。
public class Test {

    public static void main(String[] args) {
        System.out.println("Number of Arguments passed =" + args.length);
    }
}
そして、それをローカル変数に抽出したいと思います。
これを行うには、次のことが必要です。
  • アイテムを選択

  • 右クリックして* Refactor> Extract Local Variable *を選択します

    link:/uploads/Eclipse-refactor-21-100x52.png%20100w []
    *最後の手順は、キーボードショートカット_Alt Shift L_ *でも実行できます。 これで、ローカル変数を抽出できます。
    link:/uploads/Eclipse-refactor-11-100x39.png%20100w []
    そして、このリファクタリングの結果は次のとおりです。
public class Test {

    public static void main(String[] args) {
        final String prefix = "Number of Arguments passed =";
        System.out.println(prefix + args.length);
    }
}

3.6. 定数を抽出する

または、式とリテラル値を_static final_クラス属性に抽出できます。
先ほど見たように、__3.14 __valueをローカル変数に抽出できました。
public class MathUtil {

    public double circumference(double radius) {
        return 2 * 3.14 * radius;
    }
}
ただし、定数として抽出する方が適切な場合があります。
  • アイテムを選択

  • 右クリックして、[_ *リファクタリング]> [定数の抽出] * _を選択します。

    link:/uploads/Eclipse-refactor-22-100x60.png%20100w []
    これにより、他のいくつかのオプションとともに、定数に名前を付けてその可視性を設定できるダイアログが開きます。
    link:/uploads/Eclipse-refactor-12-100x47.png%20100w []
    これで、コードはもう少し読みやすくなりました。
public class MathUtil {

    private static final double PI = 3.14;

    public double circumference(double radius) {
        return 2 * PI * radius;
    }
}

4. インライン展開

また、他の方法でインラインコードを実行することもできます。
一度しか使用されないローカル変数を持つ__Util __classを考えてみましょう:
public class Util {

    public void isNumberPrime(int num) {
        boolean result = isPrime(num);
        if (result) {
            System.out.println("Number is Prime");
        } else {
            System.out.println("Number is Not Prime");
        }
    }

    // isPrime method
}
_result_ローカル変数を削除し、_isPrime_メソッド呼び出しをインライン化します。 これを行うには、次の手順に従います。
  • インライン化するアイテムを選択します

  • 右クリックして、[_リファクタリング]> [インライン_オプション]を選択します*

    link:/uploads/Eclipse-refactor-23-100x67.png%20100w []
    *最後の手順は、キーボードショートカット_Alt Shift I _:*でも実行できます。
    link:/uploads/Eclipse-refactor-13-100x37.png%20100w []
    その後、以下を追跡する変数が1つ少なくなります。
public class Util {

    public void isNumberPrime(int num) {
        if (isPrime(num)) {
            System.out.println("Number is Prime");
        } else {
            System.out.println("Number is Not Prime");
        }
    }

    // isPrime method
}

5. プッシュダウンおよびプルアップ

クラス間に親子関係(前の_Employee_や_Person_の例のような)があり、特定のメソッドや変数をクラス間で移動したい場合、Eclipseが提供するプッシュ/プルオプションを使用できます。
名前が示すように、_Push Down_オプションはメソッドとフィールドを親クラスからすべての子クラスに移動し、_Pull Up_はメソッドとフィールドを特定の子クラスから親に移動し、そのメソッドをすべての子クラスで使用できるようにします。
メソッドを子クラスに移動するには、クラス内の任意の場所を右クリックして、[_リファクタリング]> [プッシュダウン]オプションを選択する必要があります*:
link:/uploads/Eclipse-refactor-24-100x58.png%20100w []
これにより、プッシュダウンするアイテムを選択できるウィザードが開きます。
link:/uploads/Eclipse-refactor-15-100x76.png%20100w []
同様に、メソッドを子クラスから親クラスに移動するには、クラス内の任意の場所で*右クリックし、_Refactor> Pull Up_ *を選択する必要があります。
link:/uploads/Eclipse-refactor-25-100x51.png%20100w []
これにより、プルアップするアイテムを選択できる同様のウィザードが開きます。
link:/uploads/Eclipse-refactor-16-100x103.png%20100w []

6. メソッドシグネチャの変更

既存のメソッドのメソッドシグネチャを変更するには、いくつかの簡単な手順を実行できます。
  • メソッドを選択するか、カーソルを内部のどこかに配置します

  • 右クリックして[_リファクタリング]> [メソッドシグネチャの変更]を選択します

    *最後の手順は、キーボードショートカット_Alt Shift C ._ *でも実行できます。
    これにより、ポップアップが開き、それに応じてメソッドシグネチャを変更できます。
    link:/uploads/Eclipse-refactor-17-100x57.png%20100w []

7. 動く

時には、単にメソッドを別の既存のクラスに移動して、コードをよりオブジェクト指向にしたい場合があります*。
_Movie_クラスがあるシナリオを考えてみましょう。
public class Movie {

    private String title;
    private double price;
    private MovieType type;

    // other methods
}
_MovieType_は単純な列挙型です。
public enum MovieType {
    NEW, REGULAR
}
また、_Customer_が_NEW_の映画をレンタルする場合、さらに2ドル請求されるという要件があり、_Customer_クラスには_totalCost_()を計算する次のロジックがあると仮定します。
public class Customer {

    private String name;
    private String address;
    private List<Movie> movies;

    public double totalCost() {
        double result = 0;
        for (Movie movie : movies) {
            result += movieCost(movie);
        }
        return result;
    }

    private double movieCost(Movie movie) {
        if (movie.getType()
            .equals(MovieType.NEW)) {
            return 2 + movie.getPrice();
        }
        return movie.getPrice();
    }

    // other methods
}
明らかに、_MovieType_に基づくムービーコストの計算は、_Customer_クラスではなく、_Movie_クラスにより適切に配置されます。 Eclipseでこの計算ロジックを簡単に移動できます。
  • 移動する行を選択します

  • 右クリックして_Refactor> Move_オプションを選択

    *最後の手順は、キーボードショートカット_Alt Shift V _:*でも実行できます。
    link:/uploads/Eclipse-refactor-18-100x47.png%20100w []
    Eclipseは、このロジックを_Movie_クラスに含める必要があることを十分に理解しています。 必要に応じて、他の詳細オプションとともにメソッド名を変更できます。
    最終的な_Customer_クラスコードは、次のようにリファクタリングされます。
public class Customer {

    private String name;
    private String address;
    private List<Movie> movies;

    public double totalCost() {
        double result = 0;
        for (Movie movie : movies) {
            result += movie.movieCost();
        }
        return result;
    }

    // other methods
}
ご覧のとおり、_movieCost_メソッドは_Movie_クラスに移動され、リファクタリングされた_Customer_クラスで使用されています。

8. 結論

このチュートリアルでは、Eclipseが提供する主要なリファクタリング手法のいくつかを検討しました。 名前の変更や抽出などの基本的なリファクタリングから始めました。 後で、メソッドとフィールドを異なるクラスに移動するのを見ました。
詳細については、常にhttps://help.eclipse.org/kepler/topic/org.eclipse.jdt.doc.user/reference/ref-menu-refactor.htm [リファクタリングに関するEclipseの公式ドキュメント]を参照できます。 。