- PR -

インターフェイスによる継承と抽象化クラスによる継承の使い分け

投稿者投稿内容
まどか
ぬし
会議室デビュー日: 2005/09/06
投稿数: 372
お住まい・勤務地: ますのすし管区
投稿日時: 2007-08-29 15:56
引用:

基底クラスに求められている責務を明らかにするのが先と思います。


ですね。

・あああ、いいい、うううのそれぞれの役割は何か。
・それぞれの関係は、is Aか、as Aか、どちらでもないか。
これの結果から各メンバを、継承すべきか、インターフェースにするべきか、独自の実装なのか、が決まります。

なので、
引用:

「あああ」クラスでも「いいい」クラスでもCメソッドの内容が違う場合は、
オーバーライドを使うと、抽象化クラス(親クラス)では、空のCメソッドを実装しなければなりません。その点が気持ち悪いというか、引っかかるのです。


「抽象化クラス(親クラス)では、空のCメソッドを実装しなければなりません。」というこの言葉が表す必然性は生まれません。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2007-08-29 16:33
引用:

モンジさんの書き込み (2007-08-29 12:39) より:
例えば、「あああ」と「いいい」クラスがあり、
メソッドA()とB()は内容も同じ、C()は内容が違う場合、
A()、B()メソッドのみ抽象化クラスとし、C()メソッドはインターフェイス
として、「あああ」、「いいい」クラスはそれぞれを実装すればいいのでしょうか。


引用:

モンジさんの書き込み (2007-08-29 12:39) より:
また、「あああ」「いいい」「ううう」という3つのクラスがあり、
「いいい」クラスのCメソッドだけ内容が違う場合、
インターフェイスを継承するのか、抽象クラスを継承して、
「いいい」クラスのCメソッドだけオーバーライドして、
内容を記述するのか、そのあたりの使い分けについて、意見をいただけないでしょうか。


引用:

モンジさんの書き込み (2007-08-29 13:00) より:
Cメソッドが抽象クラスの機能であって、継承先では処理内容が異なる場合、
抽象クラスでCメソッドでは実装せず、継承先クラスでは、Cメソッドは
オーバーライドにて処理内容を記述するのですか。


引用:

モンジさんの書き込み (2007-08-29 14:05) より:
質問させていただいた上記の例は、is-aの関係なので、継承を使うと考えられます。しかし、「あああ」クラスでも「いいい」クラスでもCメソッドの内容が違う場合は、
オーバーライドを使うと、抽象化クラス(親クラス)では、空のCメソッドを実装しなければなりません。その点が気持ち悪いというか、引っかかるのです。


ご質問中における、メソッドの「内容が同じ」や「内容が違う」という言葉は、どういうことを指されているのでしょうか?

メソッドの中のコードという意味なのでしょうか?コードが同じなら、親クラスで実装してしまえばよく、子クラスはなにもしなくても良いのではないでしょうか。コードが違うのならば、そのための継承です。子クラスごとに実装が異なるのはあたりまえです。

それとも、ご質問は、そういうことではなく、interface を使ったほうが良いのか interface を使わずに abstract なメソッドでやったほうが良いのか?ということでしょうか?これはあまり本質的な違いはないと思います。

それとも abstract ではないメソッドが親クラスにあった場合、子クラスでメソッドをオーバーライドすべきか、という疑問でしょうか?すでに実装済みのメソッドを、子クラスでオーバーライドするのは、「改造」といった趣が出てきて汚いことであり、あまりやらないです。プログラムの改訂や多人数での開発だと、開発のしやすさを優先してこういうことをすることもありますが、シンプルさがなくなります。

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}
IIJIMAS
ベテラン
会議室デビュー日: 2006/12/06
投稿数: 77
投稿日時: 2007-08-29 17:07
話が進んでいる中、横入りすいません、
引用:

モンジさんの書き込み (2007-08-29 14:05) より:
IIJIMASさん、レスありがとうございます。

引用:

インターフェイスの方は実装という関係になります。
抽象クラスAと派生クラスBの関係は「BのインスタンスはAのインスタンスでもある」が成り立つことです。(よくいわれるようにis-a関係)。



is-aの関係にあるのは、インターフェイスではなく、抽象化クラスの継承関係だと思うのですが。



もともとそのつもりで書いたのですが。

段落分けてなかったから、誤解されたのだと思いますが私は
・インターフェイスと実装クラスは「実装」の関係がある
・抽象クラスと派生クラスは「継承」の関係(インスタンスでis-a関係)がある
の違いがあることを書いたつもりでした。

インターフェイスと実装クラスの方はにis-a関係が成り立つ必要はありません。

あとは皆様が書かれていることを踏まえていろいろ考えてみてください。
モンジ
ベテラン
会議室デビュー日: 2005/09/06
投稿数: 85
投稿日時: 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を継承
 色を変える() オーバーライドにて記述
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2007-08-29 18:03
AとB、CとDを分ける必要があるのか?という考察をします。

分ける必要があるのなら、今は実装が同じでも、いずれ違ってくるだろう。なので、同じコードを2回書く。

あるいは、スーパー クラスは一つで、virtual なメソッドに、デフォルト動作を書いておく。
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 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 ]
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2007-08-30 09:39
引用:

インターフェイスと実装クラスの方はにis-a関係が成り立つ必要はありません。


インターフェイスと実装クラスの関係も is-a ではありませんか?
is-a 関係とはどういうことですか?
IIJIMAS
ベテラン
会議室デビュー日: 2006/12/06
投稿数: 77
投稿日時: 2007-08-30 10:18
引用:

未記入さんの書き込み (2007-08-30 09:39) より:
引用:

インターフェイスと実装クラスの方はにis-a関係が成り立つ必要はありません。


インターフェイスと実装クラスの関係も is-a ではありませんか?
is-a 関係とはどういうことですか?


実はそういう返信あると思っていました。

ややこしいかもしれませんが、確かにプログラムの内部実装的にはインターフェースは特殊なクラスであるため、is-a関係と考えられますが、内部のことを考えてはオブジェクト指向の良さがなくなってしまうと思います。

オブジェクト指向の概念として、「インターフェース」は「実体=インスタンス」を一切持たないものなので、「実装クラスのインスタンス」はあくまでそのクラスのインスタンスであって、「インターフェースのインスタンス」ではありません。そういうものはありません。このような意味で一般的にはis-a関係ではないと思います。

「実在するもの」と「…できるもの」では本質的に違いがあると思います。

スキルアップ/キャリアアップ(JOB@IT)