- - PR -
データクラスの設計とダウンキャストの回避について
投稿者 | 投稿内容 | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-09-19 23:15
れいさん、回答ありがとうございます。
おっしゃるとおりです。 失礼しました。
equalsには独自の実装をしたいので、サブクラスで そのVO独自の比較をしています。 基底クラスにメンバは定義できないので、確かに 基底クラスとしての意味はないですね。 (インタフェースになりますか)
基底クラスに共通のメンバがあって…というのは確かにオブジェクト指向 として分かりやすいですよね。 今回の趣旨としては、データクラスを設計する場合、どうなるんだろう と悩んでましたので、投稿させて頂きました。 データクラスとしては、やはり基底クラスにメンバを置く必要はないのかなと。 そもそも、基底クラスという表現が間違ってますね。 C++の場合は、純粋仮想関数のみクラスはインタフェースということでしょうか。 結果としては、ダウンキャストは避けることにしたました。 つまり、データモデル化はやめて、コレクションを直で使う形に なりそうです。(←この部分はすでにあるので) 私個人としては、ダウンキャスト自体が悪いとは思っていませんが、 理解不足は否めないので、踏み切れないです。 ただ、データクラスのあるべき姿がいまいちよく分かっていないので、 まだまだ、いろいろ試してみようと思っています。 とりあえず、時間があるときにオープンソースのORマッピングの中身で も除いて、何か進展があればという感じです。 | ||||||||||||||||||||||||
|
投稿日時: 2007-09-19 23:28
一郎さん、回答ありがとうございます。
ソフトウェアレイヤーの位置づけ的に、「何か」をするというのはクライアントの自由にしたいと思っています。 つまり、データクラスは基盤として、いろいろなサブシステムに提供する予定です。
最近、書籍でダウンキャストは避けるべきというを見てから、 ちょっと踏み切れないでいます。Clientは必ず知っているので、 ダウンキャストしてもいいとは思うのですが。 ちなみに書籍は「EffectiveC++」。私には難しい部分もあり、 理解できるようになるまでは、とりあえず従っておくかみたいな…。
HolderからSearchを実行する際、どうしても戻り値が共通の型である必要があります。 そもそもの構成が悪いのか…。あるべき姿は自分の中で確立したいので、 まだまだ調べようと思っています。 | ||||||||||||||||||||||||
|
投稿日時: 2007-09-20 08:44
これを読んで気づいたのですが、ダウンキャストは、使うときに、 (1) キャスト可能か調べる必要がある場合。 (2) キャスト可能か調べる必要がない場合。 の2つに大きく分けられると思います。(1) は、たとえば Java だったら instanceof で調べたり、あるいは、たとえば、変数に入っているクラスがどれであるかを示す目印を別途設けた int や enum の変数に格納しておいたりするやりかたで、変数にどんなクラスが入っているかをなんらかの方法で調べないと分からない(使えない)場合です。 Generics を使うことで避けられるのは (2) の場合であり、(2) は結局は実質的にはダウンキャストではないと思います。
今回の場合は、(1)であり、本当のダウンキャストですよね。アプリケーションならば避けたいところですが、ミドルウェア的なものもので、それがメタデーターを扱うようなものならば、どこかで型を取り扱う必要があると思います。それならば、それを言語に組み込まれたキャストの機能でやりくりするのも良いのかな、と思います。 -- unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86} | ||||||||||||||||||||||||
|
投稿日時: 2007-09-20 12:51
はい。私もデータクラスと認識した上で回答しました。 ただ、データクラスの定義を私は知りませんが。
たとえデータクラスでも、集めるからには理由があるはずです。 その理由から導かれるメンバを基底クラスで定義するのは当然かと。 というか、共通メンバを抽出するからダウンキャストが避けられるのであって、 抽出しないのならObjectのままで集めて、 使うときにダウンキャストになってしまいます。 私には全然意味がわかりません。
言語によっていろいろあるので、継承元の一般的名称としては 基底クラスであってるかと。
データクラスの定義自体私にはわかってませんが、 私は作ってみて後悔して学ぶタイプです。 過去の資産には無駄なクラスが山のようにあります。
その場合分けの意味は私にはよくわかりません。 また、Genericを使う場合は(2)が解決されるというわけでもないです。 型引数の派生クラスをコレクションに押し込んだ場合などでは、 キャスト可能か調べないといけない場合もあります。 キャスト可能であればxxxをする、見たいな処理もありますし。
懐かしい名前です。 もう内容は覚えていません。 心を忘れてなければいいんですが。 「ダウンキャストは避けるべき」というのは、 Cなどから入った人が、ダウンキャストが多発するような コーディングをすることがよくあるので、 それを避けるための指針であると思います。 ですので、ダウンキャスト多発は結果であって原因ではありません。 ダウンキャスト回避も、目的はダウンキャスト回避ではなく、いい設計です。 こういった非オブジェクト指向プログラマのための指針はたくさんあるので、 オブジェクト指向に自信があるなら、 そんな指針に囚われる必要はないと思います。 オブジェクト指向からプログラミングに入った世代の人などには、 間違った指針である場合もあると思いますし。 とりあえず、最初からいってるように、 基底クラスにメンバがないなら、意味がないです。 ダウンキャストが多発します。 ダウンキャストが多発するから悪いのではなく、 設計が悪いからダウンキャストが多発します。 基底クラスにメンバがあり、 大抵の処理はそのメンバを使えばいいようにできてるなら、 何も問題ないと私は思います。 ダウンキャストもたまにしか必要ありません。 それは別にO/Rマッピングなどとは関係なく、 普通の話だと思うんですが。 O/Rマッピング用のクラスなら、 基底クラスのメンバを実際に用いることは少なくなるかもしれませんが、 それでも用意すべきものはたくさんあると思います。 それを忘れてしまうと後で泣けますので、ご注意を。 | ||||||||||||||||||||||||
|
投稿日時: 2007-09-20 20:00
たとえば、Java の場合、Generics が使えるようになる前までは、
のようにダウンキャストしていました。 これは、タイピングが面倒だったり、ケアレスミスで String 以外のものを入れてしまったときのデバッグに骨が折れましたが、本質的にはダウンキャストではないと考えて使っていました。なぜならば、List/ArrayList を拡張して String を引数に持つコレクションクラスを作ればそれで済んだからです。わざわざそれをしなかったのは、ダウンキャストにまつわる問題が生じているわけではなく、単純なコーディングの問題でしかなかったからだと思います。これは結局、Generics が登場して解決しました。 一方、
だと、List のような Collection に限った問題ではないはずです。 -- unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86} | ||||||||||||||||||||||||
|
投稿日時: 2007-09-22 00:07
理解できました。 理解力足りないもので…。
自分のコードをちょっと見てみましたが、 unibonさんのいうところの真のダウンキャストは結構ありました。 C#だとエラー処理のところでたくさん使ってました。 考えてみましたが、私の力+C#の機能ではダウンキャスト無しでは組めません。 やはり、綺麗に処理できるなら私は真のダウンキャストでもOK派ですね。 |