C#と諸々

C#がメインで他もまぁ諸々なブログです
おかしなこと書いてたら指摘してくれると嬉しいです(´・∀・`)
つーかコメント欲しい(´・ω・`)

2007/08/13 23:23
リスコフの置換原則 ( 以降、LSP ) は非常に興味深い。僕がオブジェクト指向の原則を学ぶきっかけとなったのが LSP だからかもしれない。

例外について見てみる。基本クラスでスローするとされていない例外は、LSP により、派生クラスでもスローしてはいけないことになる。
ここで言う "基本クラスでスローするとされていない例外" とは "基本クラスでスローしない例外" ではない。.NET なら XML コメントの <exception> セクションで宣言されていない例外のことを指している。Java は詳しくないけど Java なら throws で宣言されていない例外。 ( ※ )
これを逆に言えば、基本クラスではスローしなくとも、派生クラスでスローされる可能性があるのなら、基本クラスで宣言しなければならないということになる。でなければ LSP に違反してしまう。

ここで注意しなければいけないのが、例外の抽象度だと思う。
例えば、書籍データをデータストアから取得するための GetBookData メソッドが IBookFinderインターフェイスに定義されているとする。
IBookFinder インターフェイスを利用するアプリケーションは今の所 2 つあるとする。片方はデータストアとして XML ファイルを利用し、BookFinderFromXml クラスが IBookFinder インターフェイスを実装している。もう片方はデータストアとして DB を利用し、BookFinderFromDB クラスが IBookFinder インターフェイスを実装している。

BookFinderFromXml クラスの GetBookData メソッドは、XML ファイルが見つからなかった時に FileNotFoundException をスローする。
一方、BookFinderFromDB クラスの GetBookData メソッドは、DB が見つからなかった時に DBNotFoundException をスローする ( こんな例外 .NET に用意されていないけど )。

では、IBookFinder インターフェイスの GetBookData メソッドにはこれらの例外がスローされる可能性があると宣言するのかというと、それは違う。そんなことしてたら、派生クラスが増えるたびに、IBookFinder インターフェイスに修正をすることになるかもしれない。
ここで抽象度が出てくる。例えば DataStoreNotFoundException といった例外クラスを定義し、IBookFinder インターフェイスの GetBookData メソッドでは、この例外をスローすると宣言するべきである。派生クラスでは、FileNotFoundException や DBNotFoundException の代わりに、この例外、またはこの例外を派生させた例外 ( DataStoreFileNotFoundException とか ) をスローできる。


ちなみに、LSP に準拠させる前の BookFinderFromXml クラスは FileNotFoundException をスローしていたが、FileNotFoundException のこういう使い方は不適切な気がする。LSP とか関係なく、FileNotFoundException ではなく「データストアが存在しない」という意味の例外をスローすべきだと思う。
LSP を適用することで、この点も解消されている所が面白い。

なお、この例で挙げた設計は、僕がこの記事を書くために適当に考えただけの設計であり、実際の業務アプリには適用できない ( または適用すべきでない ) 設計かもしれない。クラス名も適当だし。あくまでも LSP と例外について書きたかっただけなので。



※ .NET と Java では例外の扱い方に大きな差があります。ここでは .NET の <exception> セクションと Java の throws を並べてますが、全く性質の異なるものです。











トラックバックURL↓
http://csharper.blog57.fc2.com/tb.php/153-d63fd063