# リファクタリング 第9章、第10章 ## 第9章 データの再編成 ### 変数の分離 変数に複数の責務が与えられている時は、変数を分離させる。 なるべく定義を一度限りとなるようにする。 #### 手順 1. 宣言時と最初の代入時の変数名を考える。 2. 可能ならば、新しい変数はconstで宣言する。 3. 2回目の代入より前にある元の変数への全ての参照を変更する。 4. テストする。 5. 代入があるごとに宣言箇所での変数名を変更し、次の代入までの参照を変更する。順次これを繰り返す。 ### フィールド名の変更 名前は非常に重要である。レコード構造のフィールド名であれば特に重要である。 #### 手順 1. レコードのスコープが限定されている場合は、そのフィールドを用いている箇所すべてを変更してテストして完了となる。 2. レコードのスコープが限定されていない場合は、まず「レコードのカプセル化」を行う。 3. 次に、オブジェクト内の非公開フィールド名を変更し、内部メソッドを調節する。 4. テストする。 5. コンストラクタがその名前を使用する場合は、「関数宣言の変更」で名前を変更する。 6. アクセサに対して「関数名の変更」を行う。 ### 問い合わせによる導出関数の置き換え 単純な計算によって、変更可能なデータを増やすことは避けるべきである。 単純な計算の変数をすべて削除することで、変更可能なデータが少なくなり、 データの意味を明確にできる。 #### 手順 1. その変数値を計算する関数を作る。 2. 「アサーションの導入」を行い、変数が使用されるたびに、計算結果が同じとなることを確認する。 3. テストする。 4. 変数の参照処理を、新たな関数呼び出しに置き換える。 5. テストする。 6. デッドコードを削除する。 ### 参照から値への変更 オブジェクトやデータ構造を入れ子にする場合、内部オブジェクトは参照あるいは値として扱える。 値オブジェクトは変更不可のため、扱いが簡単になる。 値オブジェクトにする場合は、期待するプロパティを持つ新しい内部オブジェクトに丸ごと置き換える。 #### 手順 1. 候補のクラスが変更不可になっているか、あるいは変更不可にできるかどうか確認する。 2. 各setterに対して「setterの削除」を行う。 3. 値ベースの等価判定メソッドを用意し、値オブジェクトのフィールドを用いて判定を行う。 ### 値から参照への変更 同じデータに対して複数のコピーを行うと、値が更新された際に問題となる。 この場合は、値そのものではなく、参照に変更する必要がある。 #### 手順 1. 参照オブジェクトのインスタンス用のリポジトリを作成する。 2. コンストラクタから参照オブジェクトの適切なインスタンスを検索できるようにする。 3. リポジトリを使用して、参照オブジェクトを取得するようにコンストラクタを変更する。変更の度にテストする。 ## 第10章 条件記述の単純化 ### 条件記述の分解 分岐の条件記述が長かったり複雑だったりすると、見にくく分かりにくい。 複雑な場合は分解し、関数呼び出しに置き換えるのが適当である。 **関数の抽出の特殊系だが、効果は絶大である。** #### 手順 1. 条件記述及び条件の各節に、「**関数の抽出**」を適用する。 ### 条件記述の統合 条件記述を統合する方が良い場合は、複数の条件に対して処理結果が同一の場合である。 **同一処理だと明示できる**メリットがある。 また、**統合後は「関数の抽出」が可能である。** #### 手順 1. いずれの条件判定にも副作用がないことを確認する。 2. 条件判定を二つ取り出し、論理演算子を使って統合する。 3. テストする。 4. 条件が一つになるまで繰り返す。 5. 結果として得られた条件判定に対して、「**関数の抽出**」を行う。 ### ガード節による入れ子の条件記述の置き換え ガード節とは、「正常動作」と「異常動作」に分かれている場合は、異常動作時のみ別の関数にリターンさせる判定方法である。 異常な動作に対して別途出口を設けることによって、if-else構文が等しく起こりうる正常動作であることが明確になる。 また、ガード節に変更する際、条件の書き方逆転させる(>0 ⇒ <=0)ほうが好ましい場合も多い。 #### 手順 1. 置き換えるべき条件で最も外側のものを選択し、ガード節に変更する。 2. テストする。 3. 必要に応じて繰り返す。 4. 全てのガード節が同じ結果を返す場合は、「条件記述の統合」を行う。 ### ポリモーフィズムによる条件記述の置き換え 複数の条件分岐がある場合、ポリモーフィズムを利用して、クラス毎に異なる振る舞いを定義することで置き換えられる。 特にswitch文の置き換えに効力を発揮する。型固有の振る舞いをさせることで、switch文の重複を排除できる。 また、バリエーションを持つ基本ケースをスーパークラスに入れて継承させることで、各バリエーション毎の振る舞いを表現できる。 #### 手順 1. ポリモーフィズム系クラスが存在しない場合は、そのクラスと一緒に適切なインスタンスを返すファクトリ関数を作成する。 2. 呼び出し側のコードで、ファクトリ関数を使うようにする。 3. 条件ロジックを持つ関数をスーパークラスに移動する。 4. サブクラスの一つを選んで、条件別のメソッドをオーバーライドするメソッドを作成する。条件文の該当する節の内容をサブクラスのメソッドにコピーし、適合するように調整する。 5. 条件ロジックの各節に対してこれを繰り返す。 6. スーパークラスのメソッドには、デフォルトケースを残す。スーパークラスを抽象クラスにすべき場合は、メソッド処理がサブクラスの責務であることを示すために、そのメソッドを抽象クラスとして宣言するか、メソッド内でエラーを投げる。 ### 特殊ケースの導入 コードの重複ケースとして、データ構造が特定の値かどうかを判定し、同じ処理をしているケースがある。 特殊ケースの判定はnullを用いることが多く、ヌルオブジェクトパターンと呼ばれることが多い。 こうした判定のほとんどは、簡単な呼び出しに置き換えることができる。 #### 手順 1. 前提として、プロパティを保持するデータ構造があるとする。 2. 特殊ケースの判定用プロパティをオブジェクトに追加して、falseを返す。 3. 特殊ケースのプロパティだけを持つ特殊ケース用クラスを作成し、trueを返す。 4. 特殊ケースと比較するコードに対して、「関数の抽出」を行う。全てのクライアントで新しい関数を使うようにする。 5. 新しく作成した特殊ケース用クラスをコードに導入する。特殊ケース用オブジェクトは関数呼び出しから返すか、変換関数でオブジェクトに組み込む。 6. 特殊ケースと比較する関数の本体を変更して、特殊ケース判定用プロパティを使うようにする。 7. テストする。 8. 「関数群のクラス(または変換)への集約」を行い、共通な特殊ケースの処理を特殊ケース用クラスにすべて移動させる。 9. 依然として特殊ケースの判定が必要な個所については、特殊ケース比較関数の呼び出しロジックに対し「関数のインライン化」を行う。 ### アサーションの導入 アサーションとは、ある条件が成り立つ前提条件のことである。 常に真であることを前提にした条件文であり、エラーが出ている場合はプログラマ側のコードエラーである。 デバッグのための利用の他、実行の特定時点でプログラムがある状態になっているはずであることを読み手側に伝えるツールともなる。 #### 手順 1. ある条件が真であることを前提にできる場合、そのことを明示するためにアサーションを追加する。 ###### tags: `読書`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up