リファクタリング

[扱いにくいコードについて考える] パラメータへの代入

パラメータへの代入をやめる

(What)パラメータへの代入とは何か?

パラメータとは?

「パラメータ」は本来、振る舞いの特性を表す変数のこと。
「パラメタライズ」とは、パラメータを利用して振る舞いを制御する設計のこと。

ただしパラメータは引数というインターフェースを通して受け渡されることが多いので、パラメータと引数は混同されることが多い。

パラメータへの代入とは?

メソッドに渡されたパラメータが参照するオブジェクトを変更すること。
メソッドに渡されたパラメータオブジェクトに対して、処理をすることとは異なる。

具体例は?

private int calculate(boolean val, int year, int price, int taxRate) {
    if ( year > 2014) taxRate = 1.08;
    return price *  taxRate;
}
private void multiplyQuotaBy(int multiplier, List<Salesman> list) {
  for (Salesman s : list) {
    int result = s.getQuota() * multiplier;
    s.setQuota(result);
  }
}

(How)解決策?

private int calculate(boolean val, int year, int price, int taxRate) {
    int tax = taxRate;
    if (year >= 2014) tax = 1.08;

    return price *  tax;
}

(Why)なぜパラメータへの代入が良くないのか?

まず、メソッド内でパラメータへ値を代入しても、メソッド外に変更が引き継がれない。
1. 明確さの欠如
2. 「値渡し」と「参照渡し」という混乱を招く元である

1. 明確さの欠如

与えられたものの特性を表すためだけにパラメータを使用した方が、責務がはっきりしている。
代入を許可すると、以下のように責務が一つではなくなる。
1. パラメータとして特性を表す
2. メソッドの処理結果を表す

2. 「値渡し」と「参照渡し」という混乱を招く元である

ここはあまり説明がしっくりこなかったため、自分なりの考察です。

副作用的にオブジェクトを生成したり、値を操作したりする場合は引数を明示して返してあげた方が読みやすいため。

public static void main(String[] args) {
  List<Salesman> salesGuys = getSalesmen();
  multiplyQuotaBy(2, salesGuys);
  .
  .
  .
}

private void multiplyQuotaBy(int multiplier, List<Salesman> list) {
  for (Salesman s : list) {
    int result = s.getQuota() * multiplier;
    s.setQuota(result);
  }
}
public static void main(String[] args) {
  List<Salesman> salesGuys = getSalesmen();
  List<Salesman> salesGuysWithNewQuotas = multiplyQuotaBy(2, salesGuys);
  .
  .
  .
}

private List<Salesman> multiplyQuotaBy(int multiplier, List<Salesman> list) {
  List<Salesman> resultList = new ArrayList<>(list);

  for (Salesman s : resultList) {
    int result = s.getQuota() * multiplier;
    s.setQuota(result);
  }
  return resultList;
}