第12章 設計とメタファー
本章でやったこと
大きいテストを進捗が分かるように小さいテストに分割した
1. 財布:様々な通貨や額面の紙幣が入っている財布に見立てる
概念理解用 radish-miyazaki.icon
2. 式: $5 + 10CHF という多通貨の計算を数式の評価に見立てる
実際の実装はこちらで進む radish-miyazaki.icon
メタファーを使って、最初に書いたテスト(testSimpleAddition)を書き直した
今までの章の通りに、テスト → 仮実装 → リファクタリング のサイクルを回す
ただし、明確な場合は速度を上げることもできる
多国通貨間の計算の複雑さ
問題の複雑さは「複数の通貨を扱っていることを意識させないコードにしたい」点
そもそもこれどこから出てきたのか疑問 radish-miyazaki.icon
「はじめに」に書いてあった 加重平均 云々の箇所かな 一番簡単なのは基準通貨(e.g. USドル)に変換すること
が、これだと為替レートをうまく扱えない
なぜ? radish-miyazaki.icon
いつのレートで変換したか、という情報が失われる
e.g. $5 + 10 CHF(レートが 2CHF = 1USD と仮定)
$5 + 10 CHF = $5 + $5 = $10
計算時点で 10CHF という情報は消えるため、後で 3CHF = 1USD に変わっても、$10 という値しか残っておらず変換できない
代わりに、為替レートを簡単に扱えて、計算は計算のように見えるようにしたい
これを解決するために、同じ インタフェース を持つ新しいオブジェクト(Imposter)に計算処理を委譲する これ思いつくか…? radish-miyazaki.icon
TDD はこのような優れた設計を保証するものではない
結局ひらめき 💡
が、テストとリファクタリングによって手入れされたコードがあるので、ひらめきとそれを実現するのを手助けする
Imposter pattern
既存オブジェクトが望まない振る舞いをしない場合に採用する
同じインタフェースを持ちながら、異なる実装を持つ別オブジェクト(Imposter)を作成し、そちらに処理を委譲する
code:mermaid
classDiagram
class Client {
+operation()
}
class Component {
<<interface>>
+operation()
}
class RealObject {
+operation()
}
class Imposter {
-realObjects List~Component~
+operation()
}
Client --> Component : uses
Component <|.. RealObject : implements
Component <|.. Imposter : implements
Imposter o-- Component : contains
Null Object: 「何もしない」実装を差し込む
Composite pattern: リストを単一オブジェクトに見せる
今回での採用方法
Money.plus() の戻り値の型は Expression
Money は Expression を実装している
現状は Expression は空のインタフェースなので、後からここにメソッドを追加していくんだろう radish-miyazaki.icon
換算の責務を Bank オブジェクトが持つ理由
式(Expression)が持っても良いが、以下の 2 つから専用のオブジェクトを作成
1. Expression は今回の実装のコアロジックを担うように思えるため
コアとなるオブジェクトは責務を絞った方が良い
というか 単一責任の原則... radish-miyazaki.icon 2. Expression が Fat になりそう
四則演算を始めとする、様々な演算の実装が控えている