Code Complete1人読書会 その9
第9回目。
新年も明けちゃったけどまだまだ続きます。はよ終わらせないと次に行けん。。
新年1発目はみんな大好き例外関連の話から。
正しい抽象化レベルで例外をスローする
《Code Complete 第2版 上, 2005/03/28, 日経BPソフトプレス, p.244》より
何かというと、クラスやルーチンがそのインタフェースで一貫性のある抽象化を表さなければいけないように、スローされる例外もルーチンのインタフェースの一部を表していなければならないという話。
ここに載ってるコードの例が非常にわかりやすいです。まずは悪い例から。
class Employee { ... public TaxId GetTaxId() throws EOFException { ... } ... }
GetTaxId()っていうルーチンは、何がしかの業務的な処理をしてtaxIdを呼び出し元に返却するんだろうけど、スローしてる例外がEOFExceptionっていういかにも下位レベルの実装に依存してそうな例外だという。つまり、このルーチンでは下位レベルのルーチンがスローした例外をそのまま上位の呼び出し元になげちゃってるのね。
こうすると、何がまずいかって、呼び出し元に対して実装の詳細を公開してることになっちゃう。だから、このルーチンを呼んでるクライアントコードは事実上、Employeeクラスのコードではなくて、EmployeeクラスのEOFExceptionをスローするコードと結びつくことになっちゃう。
で、カプセル化が崩壊していってしまうという*1。
例外もクラスインタフェースと一貫性のある例外を返すべきと考えると、次のようにするのが良いと。
class Employee { ... public TaxId GetTaxId() throws EmployeeDataNotAvailable { ... } ...
こうすると、スローしてる例外も業務色がグンと強くなって抽象化のレベルがクラスとそろってくるってことね*2。
もちろん、下位レベルからスローされてきた例外をcatchして投げなおす際に、情報を減らすようなことはしちゃだめです*3。そうすると、単純に例外をマッピングしなおすだけになるかもしれないけど、それでも抽象化を維持するには十分だもんね。
今日は仕事初めだったけど、久々なせいか夕方にはガッツリ疲れてしまったわ。
早く寝よう。