第10章 条件記述の単純化
条件記述の分解
大きなブロックのコードに対しては常に、コードを分解し、それぞれを意図に沿って名前をつけた関数呼び出しにすることで、意図を明確にできる
条件記述の場合、条件判定と条件ごとの処理に対して行うのがおすすめ
手順
- 条件記述および、条件の各節に関数の抽出を行う
条件記述の統合
それぞれの条件が異なるが、結果が同じ場合and,orを使って単一の結果を返す条件判定に統合する
手順
- いずれの条件判定にも副作用がないことを確認する
- 条件判定を二つ取り出し、論理演算を使って結合する
- テスト
- 条件が一つになるまで、条件判定の統合を繰り返す
- 結果として得られた、条件判定に対して関数の抽出を行うか検討する
ガード節による入子の条件式の置き換え
どちらか一方の動作が例外的な動作の場合、ガード節を使う
手順
- 置き換えるべき条件で最も外側のものを選択し、ガード節に変更する
- テスト
- 必要に応じて繰り返し
- 全てのガード節が同じ結果を返す場合は条件の統合を行う
ポリモーフィズムによる条件記述の置き換え
それぞれの型に対して異なるロジックの処理をさせる場合、ポリモーフィズムを利用して型固有の振る舞いをさせる
バリデーションを持つ、基本ケースの場合ロジックをスーパークラスに記述する
手順
- ポリモーフィックな振る舞いを持たせるクラスが存在しない場合は、そのクラスと一緒に適切なインスタンスを返すファクトリ関数を作成する
- 呼び出し側のコードで、ファクトリ関数を使うようにする
- 条件ロジックを持つスーパークラスに移動する
- サブクラスを一つ選んで、条件別のメソッドをオーバーライドするメソッドを作成する
- 条件分の該当する節の内容をサブクラスのメソッドにコピーし、適合するように調整
- 条件ロジックの各節に対して繰り返し
- スーパークラスにはデフォルトケースを残す
- スーパークラスを抽象クラスにする場合は、抽象メソッドとして宣言するかエラーを投げる
特殊ケースの導入
特殊ケースとして共通な振る舞いを備えた、オブジェクトなりクラスを作る
典型的なのが、null
手順
- 特殊ケースを判定するプロパティをオブジェクトに追加して、falseを返すようにする
- 特殊ケースを判定するプロパティだけを持つ特殊ケース用クラスを用意して、trueを返すようにする
- 特殊ケースと比較するコードに対して、関数の抽出を行う
- 新しく作成した特殊ケース用クラスをコードに導入する
- 特殊ケースと比較する関数の本体を変更して、特殊ケース判定用のプロパティを使うようにする
- テスト
- 関数群のクラスへの集約・関数群の変換への集約を使い共通な特殊ケースの処理を特殊ケース用クラスに全て移動させる
- 特殊ケースの判定が必要な箇所が残っている場合は、特殊ケース比較関数の呼び出しロジックに対して、関数のインライン化を行う
アサーションの導入
前提をアサーションで記述することで、コメントより明確になる
アサーションは常に真であることを前提とした条件分
手順
- ある条件が真であることを前提にできる場合、そのことを明示するためにアサーションを追加する
感想
条件記述の統合では、よくベイチ図を使うことが多い
(数少ない高校で習って実務で使っているやつ)
特殊ケースの導入で嬉しいことis何
少なくとも自分では使うどころが思いつかなかった
アサーションについて、確かに便利そうだけどテストじゃいかんのかって感じ
rubyで組み込むならこう?
def assert(expression)
raise AssertError unless expression
end
def division(a, b)
assert(b != 0)
a / b
end