【孤独な読書会 1-5, 1-6】 リファクタリング 5章 6章

第5章 リファクタリング・カタログに向けて

説明

6章から先のリファクタリング手法説明文の書き方の説明のみのであるため割愛。

第6章 メソッドの構成

本章からついに、リファクタリングの各手法について言及された。
以下、各手法の典型的な例を提示する。

リファクタリング手法 説明
メソッドの抽出 ひとまとめにできるコードの断片をメソッドにして、それに目的を表すような名前をつける。
メソッドのインライン化 メソッドの本体が名前を付けて呼ぶまでもなく明らかである場合に、メソッド本体を呼び出し元にインライン化してメソッドを除去する。
一時変数のインライン化 簡単な式によって一度だけ代入される一時変数があり、それが他のリファクタリングの障害となっている。
問い合わせによる一時変数の置き換え 式をメソッドに抽出する。一時変数へのすべての参照を新たなメソッドに置き換える。
説明用変数の導入 その式の結果または部分的な結果をその目的を説明する名前を付けた一時変数に格納する。
一時変数の分離 何回も代入される一時変数があるが、ループ変数でも一時変数を集める変数でもない場合に、代入ごとに別の一時変数に分ける
パラメータへの代入の除去 パラメータへの代入が行われている場合は一時変数を使う
アルゴリズムの取り換え アルゴリズムをわかりやすいものに置き換えたい場合、メソッドの本体を新たなアルゴリズムに置き換える

メソッドの抽出

ひとまとめにできるコードの断片をメソッドにして、それに目的を表すような名前をつける。

void printOwing(double amount) {
    print Banner();

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

ローカル変数が使われている場合は、上記のように"パラメータで渡す", "抽出先のメソッドの一時変数とする"など工夫が必要である。

メソッドのインライン化

メソッドの本体が名前を付けて呼ぶまでもなく明らかである場合に、メソッド本体を呼び出し元にインライン化してメソッドを除去する。

int getRating() {
    return (moreThanFiveLateDeliveries()) ? 2 : 1;
}

boolean moreThanFiveLateDeliveries() {
    return (_numberOfLateDeliveries > 5) ? 2 : 1;
}

int getRating() {
    return (_numberOfLateDeliveries > 5) ? 2: 1;
}

一時変数のインライン化

簡単な式によって一度だけ代入される一時変数があり、それが他のリファクタリングの障害となっている。

double basePrice = anOrder.basePrice();
return (basePrice > 1000);

return (anOrder.basePrice() > 1000);

問い合わせによる一時変数の置き換え

式をメソッドに抽出する。一時変数へのすべての参照を新たなメソッドに置き換える。

double basePrice = _quantity * _itemPrice;
if(basePrice > 1000)
    return basePrice * 0.95;
else
    return basePrice * 0.98;

if(basePrice > 1000)
    return basePrice() * 0.95;
else
    return basePrice() * 0.98;

・・・
double basesPrice() {
    return _quantity * _itemPrice;
}

説明用変数の導入

その式の結果または部分的な結果をその目的を説明する名前を付けた一時変数に格納する。

if((platform.toUpperCase().indexOf("MAC") > -1) &&
     browser.toUpperCase().indexOf("IE") > -1) &&
      wasInitialized() && resize > 0 )
      {
          // 略
      }

final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1;
final boolean isIEBrowser = browser.toUpperCase().indexOf("IE") > -1;
final boolean wasResized = resize > 0;

if(isMacOs && isIEBrowser && wasInitialized() && wasResized ) {
    // 略
}

一時変数の分離

何回も代入される一時変数があるが、ループ変数でも一時変数を集める変数でもない場合に、代入ごとに別の一時変数に分ける

double temp = 2 * (_height * _width);
System.out.plintln(temp);
temp = _height * _width;
System.out.plintln(temp);

final double perimeter = 2 * (_height * _width);
System.out.plintln(perimeter);
final double area =  _height * _width;
System.out.plintln(area);

パラメータへの代入の除去

パラメータへの代入が行われている場合は一時変数を使う

int discount(int inputVal, int quantity, int yearToDate) {
    if(inputVal > 50) inputVal -= 2;
}

int discount(int inputVal, int quantity, int yearToDate) {
    int result = inputVal;
    if(inputVal > 50) result -= 2;
}

メソッドオブジェクトによるメソッドの置き換え

長いメソッドで「メソッドの抽出」を適用できないようなローカル変数の使い方をしている。

class Order...{
    double price() {
        double primaryBasePrice;
        double secondaryBasePrice;
        double tertiaryBasePrice;
        // 長い処理;
        ...
    }
}

アルゴリズムの取り換え

アルゴリズムをわかりやすいものに置き換えたい場合、メソッドの本体を新たなアルゴリズムに置き換える

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

String foundPerson(String[] people) {
    List candidates = Arrays.asList(new String[] {"Don", "John", "Kent"});
    for (int i = 0; i < people.length; i++){
        if(condidates.contains(people[i]))
            return people[i];
    }
    return "";
}