- - PR -
インターフェイスによる継承と抽象化クラスによる継承の使い分け
投稿者 | 投稿内容 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-08-29 15:56
ですね。 ・あああ、いいい、うううのそれぞれの役割は何か。 ・それぞれの関係は、is Aか、as Aか、どちらでもないか。 これの結果から各メンバを、継承すべきか、インターフェースにするべきか、独自の実装なのか、が決まります。 なので、
「抽象化クラス(親クラス)では、空のCメソッドを実装しなければなりません。」というこの言葉が表す必然性は生まれません。 | ||||||||||||||||
|
投稿日時: 2007-08-29 16:33
ご質問中における、メソッドの「内容が同じ」や「内容が違う」という言葉は、どういうことを指されているのでしょうか? メソッドの中のコードという意味なのでしょうか?コードが同じなら、親クラスで実装してしまえばよく、子クラスはなにもしなくても良いのではないでしょうか。コードが違うのならば、そのための継承です。子クラスごとに実装が異なるのはあたりまえです。 それとも、ご質問は、そういうことではなく、interface を使ったほうが良いのか interface を使わずに abstract なメソッドでやったほうが良いのか?ということでしょうか?これはあまり本質的な違いはないと思います。 それとも abstract ではないメソッドが親クラスにあった場合、子クラスでメソッドをオーバーライドすべきか、という疑問でしょうか?すでに実装済みのメソッドを、子クラスでオーバーライドするのは、「改造」といった趣が出てきて汚いことであり、あまりやらないです。プログラムの改訂や多人数での開発だと、開発のしやすさを優先してこういうことをすることもありますが、シンプルさがなくなります。 -- unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86} | ||||||||||||||||
|
投稿日時: 2007-08-29 17:07
話が進んでいる中、横入りすいません、
もともとそのつもりで書いたのですが。 段落分けてなかったから、誤解されたのだと思いますが私は ・インターフェイスと実装クラスは「実装」の関係がある ・抽象クラスと派生クラスは「継承」の関係(インスタンスでis-a関係)がある の違いがあることを書いたつもりでした。 インターフェイスと実装クラスの方はにis-a関係が成り立つ必要はありません。 あとは皆様が書かれていることを踏まえていろいろ考えてみてください。 | ||||||||||||||||
|
投稿日時: 2007-08-29 17:40
IIJIMASさん
誤解しただけでした。 例題があまりに漠然としていましたので、少し変えさせていただきます。 皆様からのアドバイスで色々考えてみて、設計してみました。 (例題) WindowsアプリケーションのGridで、A、B、C、Dの4つのGridがあるとします。 共通の処理項目として、「表示する」「色を変える」があるとします。 ただし、色を変えるの内容(コード)は、ABCDすべて違うとします。 また、CとDには「明細に移動する」という処理があります。内容(コード)は同じです。 このような例の場合、 <スーパークラス1> 表示する() 色を変える() 中身は実装しない <Aクラス> ※Bクラスも同様 スーパークラス1を継承 色を変える() オーバーライドにて記述 <スーパークラス2> スーパークラス1を継承 明細に移動する() <Cクラス> ※Dクラスも同様 スーパークラス2を継承 色を変える() オーバーライドにて記述 | ||||||||||||||||
|
投稿日時: 2007-08-29 18:03
AとB、CとDを分ける必要があるのか?という考察をします。
分ける必要があるのなら、今は実装が同じでも、いずれ違ってくるだろう。なので、同じコードを2回書く。 あるいは、スーパー クラスは一つで、virtual なメソッドに、デフォルト動作を書いておく。 | ||||||||||||||||
|
投稿日時: 2007-08-29 18:24
私の場合、インターフェース実装か継承かで言えば、
NABEさんの仰られているように両方を使うことが多いです。 > また、ADO.NET 2.0のSystem.Data.Commonの設計の話などを読むと、 > 1)interfaceを用意する。 > 2)1の基本的な実装classを用意する。 > 3)2の各種派生classを実装する。 > というパタンも考慮する必要があると思われます。 ただ、エンドユーザーからは継承関係は見えませんので、 Bのグリッドでも「明細移動できるようにしてほしい」といった要望が挙がることもありますよね。 そういった場合にグリッドの型を置き換える必要がありませんか? 実際にはもっと多くの機能があるでしょうから、組み合わせ数も増えますし、 汎用性を高めたつもりがかえって制限を強くしてしまうこともあるような気がします。 > <Aクラス> ※Bクラスも同様 > スーパークラス1を継承 > 色を変える() オーバーライドにて記述 > > <スーパークラス2> > スーパークラス1を継承 > 明細に移動する() > > <Cクラス> ※Dクラスも同様 > スーパークラス2を継承 > 色を変える() オーバーライドにて記述 インターフェース実装か継承かという観点からは外れてしまいますが、 委譲を使ったほうがコードの重複や汎用性を実現しやすいのではないかと思います。 interface I色を変える { 指定された行の色を変える( グリッド target, int rowIndex); } interface I明細に移動する { 指定された行に移動する( グリッド target, int rowIndex); } 「色を変える」実装内容が異なる場合、 各実装ごとに I色を変える を実装したクラスを定義。 class 拡張グリッド : グリッド { // インターフェース型で持たせる public I明細に移動する ColorChanger { get {} set {} } public void 指定された行の色を変える( int rowIndex ) { // 設定されていなければ何もしない if ( this.ColorChanger == null ) { return; } this.ColorChanger.指定された行の色を変える( this, rowIndex ); } public bool Can指定された行の色を変える { // 設定されていれば使用可能 return this.ColorChanger != null; } //「明細に移動する」のも同様に。 } [ メッセージ編集済み 編集者: masa 編集日時 2007-08-29 18:26 ] [ メッセージ編集済み 編集者: masa 編集日時 2007-08-29 18:31 ] | ||||||||||||||||
|
投稿日時: 2007-08-30 09:39
インターフェイスと実装クラスの関係も is-a ではありませんか? is-a 関係とはどういうことですか? | ||||||||||||||||
|
投稿日時: 2007-08-30 10:18
実はそういう返信あると思っていました。 ややこしいかもしれませんが、確かにプログラムの内部実装的にはインターフェースは特殊なクラスであるため、is-a関係と考えられますが、内部のことを考えてはオブジェクト指向の良さがなくなってしまうと思います。 オブジェクト指向の概念として、「インターフェース」は「実体=インスタンス」を一切持たないものなので、「実装クラスのインスタンス」はあくまでそのクラスのインスタンスであって、「インターフェースのインスタンス」ではありません。そういうものはありません。このような意味で一般的にはis-a関係ではないと思います。 「実在するもの」と「…できるもの」では本質的に違いがあると思います。 |