質問: インタフェースとその実装クラスはis-a関係でしょうか?
回答: 簡単なお返事 ====== はい、そのとおりです。 ただし **あなたが** *インターフェイス側で期待している仕様* を満たすように、そのクラスを実装する限り。 正確なお返事 ====== `is-a` の定義について `B is-a A` とは **「Aの仕様は、Bの仕様でもある」** という関係性をいいます。 ここで仕様は * どんなメソッドがあるのか * そのメソッドは、どのような振る舞いが期待されているのか * そのクラスは全体を通して、どんな使い方ができるのか といった情報です。 もうちょっとこの定義を噛み砕くなら **Aの仕様を元に組み立てられた利用者コードに対して、Bを与えても変なことは起きない** ということです。 このことを指して **リスコフの置換原則(LSP)** とも言います。 なぜ `is-a` がこのように定義されるのか しかしこれは当然必要な性質に思えます。 なぜ `B is-a-subclass-of A` (BがAのサブクラスである) ことと、 言葉を使い分けてわざわざ `is-a` と言うのでしょうか。 それは`B is-a A` と *呼べない*(つまり、置き換えると困ってしまう) サブクラスが、 設計思想の不備により登場していた過去があるためです。 黎明期のオブジェクト指向には、 **差分プログラミング** という考え方がありました。 **差分プログラミング** とは、親クラスに無い機能を足しこんで新機能を追加するために、継承を使いましょうという考え方です。 それにより、コードを *再利用* することで生産性をあげようとしていたわけです。 差分プログラミングでは、親クラスのコードを好きなようにオーバライドします。 そのときにメソッドに期待できる仕様も勝手に書き換えてしまいます。 しかし実際のオブジェクト指向言語では、親クラスで宣言された変数には、サブクラスのインスタンスを代入できます。 いつどのサブクラスが使われるかは、コードを追ってみないとわかりません。 そのため利用者コードは、全てのサブクラスで上手く動くコードを書かなくてはいけなくなります。 よって全てのサブクラスのコードを読むまで、コードが動くかどうかわからない状態になってしまいます。 結果として全体を通してみると、コードがどんどん混乱した状態になってしまうわけです。 差分プログラミングは今日ではアンチパターンと見做されています。 一方でLSPや `is-a` と言える関係を保って継承を使うことを考えます。 するとコードの利用者は使いたい親クラスの仕様だけを気にすれば良い状態となります。 そこで `is-a` や `LSP` を **継承を使う・使わないの分け目にしよう** という発想となり、今日の設計手段が生まれたわけです。 結論 さてインターフェイスを、あるクラスに実装した時、それは `is-a` でしょうか。 正確な答えは 「はい。 **あなたが** `is-a` になるように **努力するべき** です」 となります。 特に親になるものがインタフェイスであっても、クラスであっても違いはありません。 `B is-a A` とは **「Aの仕様は、Bの仕様でもある」** という関係性のことだからです。 インターフェイス側に書いてある仕様に関するコメントや、利用側周辺コードをよく読んで、 そこに期待される仕様を満たすようにクラスを実装しましょう。 そうすることで `is-a` を保った、よいクラスを提供できるようになります。 またはインタフェイスを作成するときには、そこに期待する仕様が明らかになるようにしましょう。 コメントを残したり、サンプルとなる典型的なクラスとそのテストを示しておくことで そのインタフェイスを実装する人が、 `is-a` 関係を保てるように、促してあげるわけです。