- - PR -
インターフェイスによる継承と抽象化クラスによる継承の使い分け
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-08-30 10:29
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 ] | ||||||||
|
投稿日時: 2007-08-30 11:38
C++ では、純粋仮想クラスを基底クラスにすることでインターフェースを実装することを表現するし、C# なんかではモロに継承と同じ構文でそのクラスがインターフェースを実装することを表すので、混同しやすいのかもしれないですね。 Java が、クラス継承とインターフェースの実装で extends と implements キーワードを使い分けるのは、その辺を区別するためなのかもしれませんね。 | ||||||||
|
投稿日時: 2007-09-01 21:31
こんな説明はどうでしょうか
鳥は飛べる。カラスは飛べる 飛行機も飛べる。 カラスは鳥であるが成り立つのでis-aの関係。飛行機は鳥であるは成り立たないのでis-aの関係ではない。しかし、飛ぶ機能という観点でみると鳥もカラスも飛行機も同じで特定の機能を有している関係として考えれます。なのでインタフェースは特定の機能を提供することと捉える事ができます。(視点が違うという例えです) プログラミング的に考えると、インタフェースは利用上の契約という位置づけで内部的な実装よりは外部との約束を表現したものと捉える考え方があります。 以下の資料も面白いので参考にされると良いとおもいます。 ロールインタフェース http://capsctrl.que.jp/kdmsnr/wiki/bliki/?RoleInterface | ||||||||
|
投稿日時: 2007-09-03 10:40
もしかして私に説明してくれているのかな? 私は is-a かどうかがインターフェイスにするか抽象クラスにするかの決定要因にはならないと思っていますが、どうやらこの話は不毛なことになることが多いようなのでやめておこうと思いました。
アホですか? それはインターフェイスもクラス階層のどちらでもない概念だから成り立たないのでしょう? ふつーはこうなります↓
「飛べるもの」はインターフェイスでもいいし抽象クラスでもいい。コードの再利用性が高いなら抽象クラスにすればいいし。抽象クラスにしたところで、メソッドが実装されていないとか、多くの場合、サブクラスでオーバーライドされることが予想されるならインターフェイスにしたほうがよい。あくまでコードの再利用という視点でインターフェイスか抽象クラスか決める程度のこと。(あとは単一継承制限による止むを得なさか。) 「実在するもの」と「…できるもの」という違いだと言っている人もいたけど、それにも反対します。まず、「飛べるものインターフェイス」は「飛べるもの抽象クラス」と同程度に「実在します」。それからインターフェイスを「…できるもの」と捉えるのもおかしい。あくまでそういう利用をされているというだけであって。 インターフェイスは「has a capability」「has a role」「has a function」「has a responsibility」に限定されるものではないと思います。 参考までに Java で以前あった論争 abstract class and interface abstract class and interface | ||||||||
|
投稿日時: 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のように振舞うとかじゃだめです。 | ||||||||
|
投稿日時: 2007-09-03 11:32
あと実装に近い話ですが、
多分、例として考えただけで実際にこういう実装をしたわけではないと思いますが、この「明細に移動する」というのはどれほど汎用的な処理を想定されてますか。 ある特定の画面のためのものといったような専用の処理なら、その使用する側(画面)の方に書いてしまった方が分かりやすいです。 ・社員検索画面のIDのTextBox ・社員検索画面の名前のTextBox ・社員検索画面の性別のRadioButton といった一か所でしか使わないクラスを作り、そこに機能を実装して処理することもできるにはできますが、特別な理由が無い限りは止めておいた方がいいです。 社員検索画面のIDのTextBoxはTextBoxなので、継承関係として間違っているわけではありませんが。 しかし、スーパークラス2を継承して複数のクラスを作っているということは、ある特定の画面の処理じゃないのかもしれませんね。 それならA,Bに「明細に移動する」機能があってもいいんじゃないでしょうか。使わなければ。 TextBoxを使う時だって、いつもどこでも全ての機能を使っているわけではありませんよね。 継承は、正しく使うとソースコードを理解させやすくしますが、使いすぎると逆に理解しづらくなります。正しい使い方だったとしても。 じっくり考えれば確かにそういった継承関係にあると分かるものでも継承ツリーが深くなっていると、人間の脳が直感で理解できなくなるんでしょうね。 | ||||||||
|
投稿日時: 2007-09-03 13:03
そう言っていいた人です。 またたとえで恐縮ですが、 四辺あるジグソーパズル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
どういう場合があるのでしょうか、知りたいのでよろしければここに例をあげていただけませんか。 | ||||||||
|
投稿日時: 2007-09-03 13:57
いくら例を出されてもねえ。それってあなたのインターフェイス/抽象クラスの決定スタンスに合わせて例を出しているだけでしょう?私はもっと広範にインターフェイスを使ってよいと考えています。実際、単一継承という言語仕様の制限によって、あなたのスタンスに合わないものをインターフェイスとして実装しなければいけない事実をあなた自身で見つけられるはずですよ?
・抽象クラス:ジグソーパズル 1ピースの一辺の形状 ・サブクラス:ジグソーパズルの 1ピースの輪郭 ・集約クラス:ジグソーパズルの 1ピース(輪郭をあらわすメンバー 4つを保持している north, east, west, south) という設計もできますよね。あなたの設計では 4辺の形状組み合わせで実装クラスが膨大に膨れ上がってしまいますので、この場合なら集約を使ったほうがいいでしょう。無理にインターフェイス、抽象クラス、実装クラスを使って例示しようとするから設計自体がおかしくなっているんです。
「くだもの」インターフェイスを実装した「りんご」クラス。 |