抽象クラスもインターフェースも通常のクラスとのコーディング上の違いを理解しても、実際のプログラミングではどのように使い分けたらよいのでしょうか。
どのような場合はクラス、どのような場合に抽象クラス、そしてどういう時にはインターフェースを使ってプログラミングすれば良いのか、いくつかのガイドを整理します。
クラスと抽象クラスの使い分け
クラスはもともと(狭義の)オブジェクトを抽象化して作ります。
では抽象クラスは一般的なクラスと何が違うのでしょう。本題に入る前に「抽象」という言葉を正しく理解しましょう。
「抽象」というと抽象画の印象や、「具象」の反対語だから「曖昧な」といった意味だろうと思っている人もいます。ですが英語のabstractには「曖昧な」という意味はありません。英語の辞書を見ると、動詞として「~を取り除く」「~を概念化する」「~要約する」とあります。
ここで概念化とは「いくつかの事物を一般化して考えるさま」ですから、抽象化とは「個別的な物を取り除いて、事物に共通なものを抜き出し、要約する」ことです。クラスは個々のオブジェクトから個別的な物を取り除き、共通する点を抜き出して、具体的なフィールドとメソッドに要約してスーパークラスとし、各オブジェクト固有の事物をサブクラスで定義します。
一方、抽象クラスはこの抽象化を一歩進めて、個別的な物の中で振舞いの中身は違っていても、共通して持っている振舞いを中身を定義しない抽象メソッドとして定義し、サブクラスに具体的な振舞の中身を定義させます。従って抽象クラスは通常のスーパークラスが行わない定義すべき振舞いをサブクラスに強制力を持って規定します。
抽象クラスとインターフェース
一般的なクラスと違いはあるといっても抽象クラスはクラスですからobjectからのクラスの階層構造のどこかに位置します。一方インターフェースは外見的に抽象クラスと似ていてもクラスではないので、この階層構造の中には位置しません。
インターフェースは特定のクラスに付随するだけです。このためクラスが継承されるのに対し、インターフェースは実装されるという違いになります。この点こそが抽象クラスとインターフェースの違いであり、使い分けのポイントです。
意味から考えるとインターフェースは「つなぎ合わせる」「調和させる」とあります。では何をつなぎ合わせ、調和させるのでしょう。
実際の開発では大勢のプログラマがプログラミングを分担し、数多くの機能(振舞い)を開発するので、全ての開発が同期して開発できるわけではありません。つまりある部分を開発し、テストしようとしても関連する別の部分はまだ設計中で結合してテストすることが出来なかったり、開発している場所が離れていてリアルタイムで開発を同期させることが出来なかったり、そもそもシステムが複雑で部分部分を個別にテストしてからでないと結合してテストが出来なかったりします。
このような場合、インターフェースを使えば複雑なシステムをモジュールに分解して、モジュール単位で開発を進め、単体テストが終わったら実装モジュールを実際の物に入れ替えて総合テストを行う事ができます。つまりインターフェースは実装の仕方は問わずに相手にしてもらいたい事だけを定義し、自分と相手モジュールをつなぎます。このため抽象クラスと違って相手に与える定数と相手に求める振舞いとしての抽象メソッドしか記述しません。