- PR -

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

投稿者投稿内容
よねKEN
ぬし
会議室デビュー日: 2003/08/23
投稿数: 472
投稿日時: 2007-08-30 10:29
引用:

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

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


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



is-aはスーパークラスとサブクラス間の関係はこうあるべきということを
説明するときによく用いられる標語のようなものですね。

A lion is an animalのようにA(ライオン) ≒ B(動物)の関係を示して"is-a"と呼ばれることがあります。
同様の内容で"is-kind-of"という説明がなされることもありますね。

インタフェースの場合、
インタフェースBと実装クラスAの間は通常、「≒」の関係ではないので、
is-aとは言えないと思います。

インタフェースを説明する上で、そういった標語を見たことが無いので、
なんと例えるのがよいかはわかりませんが、あえて例えるなら、
「A has a capability of B」
こんな感じでしょうか。
# capability = 能力。英文としての妥当性は横においといてください、雰囲気ですので。

<追記>
・例えに出てくるAとBの関係が前半と後半で逆になっていたので訂正。
・未記入さんの意図を読みきれずに、釈迦に説法になっている気がしてきた・・・。
・インタフェースに関して、A has a role/function of B
という説明をしているサイトを発見。こちらの方がよさそう。
</追記>

[ メッセージ編集済み 編集者: よねKEN 編集日時 2007-08-30 10:33 ]

[ メッセージ編集済み 編集者: よねKEN 編集日時 2007-08-30 10:40 ]
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2007-08-30 11:38
引用:

インタフェースの場合、
インタフェースBと実装クラスAの間は通常、「≒」の関係ではないので、
is-aとは言えないと思います。



C++ では、純粋仮想クラスを基底クラスにすることでインターフェースを実装することを表現するし、C# なんかではモロに継承と同じ構文でそのクラスがインターフェースを実装することを表すので、混同しやすいのかもしれないですね。

Java が、クラス継承とインターフェースの実装で extends と implements キーワードを使い分けるのは、その辺を区別するためなのかもしれませんね。
dotnetmemo
常連さん
会議室デビュー日: 2006/04/29
投稿数: 24
投稿日時: 2007-09-01 21:31
こんな説明はどうでしょうか

鳥は飛べる。カラスは飛べる
飛行機も飛べる。

カラスは鳥であるが成り立つのでis-aの関係。飛行機は鳥であるは成り立たないのでis-aの関係ではない。しかし、飛ぶ機能という観点でみると鳥もカラスも飛行機も同じで特定の機能を有している関係として考えれます。なのでインタフェースは特定の機能を提供することと捉える事ができます。(視点が違うという例えです)

プログラミング的に考えると、インタフェースは利用上の契約という位置づけで内部的な実装よりは外部との約束を表現したものと捉える考え方があります。

以下の資料も面白いので参考にされると良いとおもいます。

ロールインタフェース
http://capsctrl.que.jp/kdmsnr/wiki/bliki/?RoleInterface

未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2007-09-03 10:40
もしかして私に説明してくれているのかな? 私は is-a かどうかがインターフェイスにするか抽象クラスにするかの決定要因にはならないと思っていますが、どうやらこの話は不毛なことになることが多いようなのでやめておこうと思いました。

引用:

飛行機は鳥であるは成り立たないのでis-aの関係ではない。


アホですか? それはインターフェイスもクラス階層のどちらでもない概念だから成り立たないのでしょう? ふつーはこうなります↓

コード:
飛べるもの----鳥----カラス
          |
          +---飛行機----セスナ


「飛べるもの」はインターフェイスでもいいし抽象クラスでもいい。コードの再利用性が高いなら抽象クラスにすればいいし。抽象クラスにしたところで、メソッドが実装されていないとか、多くの場合、サブクラスでオーバーライドされることが予想されるならインターフェイスにしたほうがよい。あくまでコードの再利用という視点でインターフェイスか抽象クラスか決める程度のこと。(あとは単一継承制限による止むを得なさか。)

「実在するもの」と「…できるもの」という違いだと言っている人もいたけど、それにも反対します。まず、「飛べるものインターフェイス」は「飛べるもの抽象クラス」と同程度に「実在します」。それからインターフェイスを「…できるもの」と捉えるのもおかしい。あくまでそういう利用をされているというだけであって。

インターフェイスは「has a capability」「has a role」「has a function」「has a responsibility」に限定されるものではないと思います。

参考までに Java で以前あった論争

abstract class and interface
abstract class and interface
一郎
ぬし
会議室デビュー日: 2002/10/11
投稿数: 1081
投稿日時: 2007-09-03 11:31
みなさんの書き込みをみて思いついたんですが、こういう考えはどうでしょう。

インターフェイスというのは外部に公開するサービス(メソッドやプロパティ等)の定義のセットです。
クラスに、インターフェイスを使わずに普通にサービスを実装した場合も外部からそれを見ることができます。
ですので、インターフェイスを使わずに作られたクラスも、そのクラスに対応する「無名のインターフェイス」的なものが勝手に作られると考えるんです。
Aクラスを作るとそれに対応するインターフェイス(便宜上IAと呼ぶ)も勝手に作られ、Aを継承してBクラスを作るともちろんBもIAを実装しているため継承とインターフェイスの実装が同じように見える、と。

AがICというインターフェイスを実装していた場合に、ICのサービスの実装はするけど同じサービスをIAの方には含めないということもできます。(C#では「明示的なインターフェイスの実装」、VBではどうやるか知らない)
これはまさに、クラスは実装しているインターフェイス以外にもうひとつ独自のインターフェイスを持っているということではないでしょうか。

dotnetmemoさんの例だと、
・鳥も飛行機も「飛ぶ」というサービスを提供している。つまり「飛ぶインターフェイス」を実装している。
・カラスは鳥なので、鳥を継承している。そのため「飛ぶインターフェイス」も受け継いでいる。
・飛行機と鳥やカラスに関連はないので継承したりはしない。

継承すると結果的にインターフェイスも引き継がれるだけで、同じサービスを提供するからといって継承関係を使うのは間違っているということです。
Aを継承してBを作っていいのは、その問題領域でBがAであると認識されているときだけです。
Aの機能を使っているとか、Aに似ているとか、Aのように振舞うとかじゃだめです。
一郎
ぬし
会議室デビュー日: 2002/10/11
投稿数: 1081
投稿日時: 2007-09-03 11:32
あと実装に近い話ですが、
引用:

モンジさんの書き込み (2007-08-29 17:40) より:
また、CとDには「明細に移動する」という処理があります。内容(コード)は同じです。

<スーパークラス2>
 スーパークラス1を継承
 明細に移動する()

<Cクラス> ※Dクラスも同様
 スーパークラス2を継承
 色を変える() オーバーライドにて記述


多分、例として考えただけで実際にこういう実装をしたわけではないと思いますが、この「明細に移動する」というのはどれほど汎用的な処理を想定されてますか。
ある特定の画面のためのものといったような専用の処理なら、その使用する側(画面)の方に書いてしまった方が分かりやすいです。
・社員検索画面のIDのTextBox
・社員検索画面の名前のTextBox
・社員検索画面の性別のRadioButton
といった一か所でしか使わないクラスを作り、そこに機能を実装して処理することもできるにはできますが、特別な理由が無い限りは止めておいた方がいいです。
社員検索画面のIDのTextBoxはTextBoxなので、継承関係として間違っているわけではありませんが。

しかし、スーパークラス2を継承して複数のクラスを作っているということは、ある特定の画面の処理じゃないのかもしれませんね。
それならA,Bに「明細に移動する」機能があってもいいんじゃないでしょうか。使わなければ。
TextBoxを使う時だって、いつもどこでも全ての機能を使っているわけではありませんよね。

継承は、正しく使うとソースコードを理解させやすくしますが、使いすぎると逆に理解しづらくなります。正しい使い方だったとしても。
じっくり考えれば確かにそういった継承関係にあると分かるものでも継承ツリーが深くなっていると、人間の脳が直感で理解できなくなるんでしょうね。
IIJIMAS
ベテラン
会議室デビュー日: 2006/12/06
投稿数: 77
投稿日時: 2007-09-03 13:03
引用:

未記入さんの書き込み (2007-09-03 10:40) より:

「実在するもの」と「…できるもの」という違いだと言っている人もいたけど、それにも反対します。まず、「飛べるものインターフェイス」は「飛べるもの抽象クラス」と同程度に「実在します」。それからインターフェイスを「…できるもの」と捉えるのもおかしい。あくまでそういう利用をされているというだけであって。


そう言っていいた人です。

またたとえで恐縮ですが、
四辺あるジグソーパズル1ピースでたとえると、
・インターフェース : ジグソーパズル1ピースの一辺の形状
・抽象クラス : ジグソーパズルの1ピースの輪郭
・実装クラス : ジグソーパズルの1ピース
という感じに捉えられませんか。

また、
抽象クラスと派生クラスは「継承」の関係はIS A関係と呼ばれている対して、
インターフェイスと実装クラスの「実装」の関係はCAN DO関係と呼ばれているそうです。

ソース:
MSDN
Dr GUI.NET
Dr. GUI .NET 1.1 #2
http://msdn2.microsoft.com/en-us/library/aa302308.aspx
のInterfaces vs. Abstract Base Classes

引用:

インターフェイスは「has a capability」「has a role」「has a function」「has a responsibility」に限定されるものではないと思います。


どういう場合があるのでしょうか、知りたいのでよろしければここに例をあげていただけませんか。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2007-09-03 13:57
いくら例を出されてもねえ。それってあなたのインターフェイス/抽象クラスの決定スタンスに合わせて例を出しているだけでしょう?私はもっと広範にインターフェイスを使ってよいと考えています。実際、単一継承という言語仕様の制限によって、あなたのスタンスに合わないものをインターフェイスとして実装しなければいけない事実をあなた自身で見つけられるはずですよ?

引用:

四辺あるジグソーパズル1ピースでたとえると、
・インターフェース : ジグソーパズル1ピースの一辺の形状
・抽象クラス : ジグソーパズルの1ピースの輪郭
・実装クラス : ジグソーパズルの1ピース
という感じに捉えられませんか。


・抽象クラス:ジグソーパズル 1ピースの一辺の形状
・サブクラス:ジグソーパズルの 1ピースの輪郭
・集約クラス:ジグソーパズルの 1ピース(輪郭をあらわすメンバー 4つを保持している north, east, west, south)

という設計もできますよね。あなたの設計では 4辺の形状組み合わせで実装クラスが膨大に膨れ上がってしまいますので、この場合なら集約を使ったほうがいいでしょう。無理にインターフェイス、抽象クラス、実装クラスを使って例示しようとするから設計自体がおかしくなっているんです。

引用:

どういう場合があるのでしょうか、知りたいのでよろしければここに例をあげていただけませんか。



「くだもの」インターフェイスを実装した「りんご」クラス。

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