この記事で分かること
- 抽象クラスとインターフェースの違いやメリットについて
- 抽象クラスとインターフェースの使い分け方
- 抽象クラスとインターフェースについて概念的な理解ができる
この記事では、オブジェクト指向における抽象クラスとインターフェースの概念的な違いをできるだけ分かりやすく解説します。
プログラミング初心者にとって、オブジェクト指向を完全に理解したと言えるまでにはかなり高いハードルがあると思いますが、その中でも抽象クラス (abstract class)とインターフェース (interface)の違いを明確に答えられる人は少ないのではないでしょうか?
この記事を読めば、似て非なる概念である抽象クラスとインターフェースについて理解し、どのように使い分ければ良いかが分かります。
私はGoF本を15年以上前に読んでから、ずっと仕事でオブジェクト指向を使い続けています。
初心者には取っ付きにくい表現があるかも知れませんが、本質的な理解ができるように丁寧に解説していますので、最後まで読んでいただけると嬉しいです。
嬉しいお知らせ
この記事が本ブログで最も高評価を得ており、なんと約90%の方が「役に立った」と回答してくださいました。
フィードバックを頂いた皆さん、本当にありがとうございます!
結論から
極限までシンプルに説明します。
- 抽象クラスは もの を定義する
- インターフェースは ふるまい を定義する
まずは、プログラミング言語でどのように実装するのかは置いといて、概念の違いをしっかりと認識しましょう。
どう使い分けるかは後ほど説明します。
オブジェクト指向の考え方は、プログラミング言語とは関係ありません。
一度理解してしまえば、どのような言語にも応用することができるものです。
よくある間違い
- 抽象クラス:共通のメンバ、メソッドを持ち派生先で再利用するためのクラス。また、公開メソッドの実装を強制する
- インターフェース:公開メソッドのみを定義したもので、クラスにメソッドの実装を強制する
という理解をしている方は使い方を把握しているだけで、概念的な理解が足りてないと思います。
以降の章では、これらの概念を本質的に理解できるように説明していきます。
抽象クラスとは?
抽象クラスとは概念的に もの(Object) を表すものです。
もの の中でも、抽象的なもの を表しています。
抽象的なものとは何か?それは、ある共通項を持つもの です。
言葉だけだと分かりにくいので、例を挙げてみましょう!
抽象クラスの例
- 動物
- 車
- 帽子
- 学校
プログラムで、人間・猿・鳥・犬・猫を扱う必要がある場合に、それらを一言で表す言葉として自然に 動物 という概念が浮かぶと思います
抽象クラスとはそのような具体的なもの達の共通項を抜き出してグルーピングしたもの です。
同じように、
- 電気自動車・ハイブリッド車・トラックを抽象化したものが 車 です。
- ハット・キャップ・ハンチング帽を抽象化したものが 帽子 です。
- 小学校・中学校・高校・大学を抽象化したものが 学校 です。
いずれも、is-a 関係になっています。
- 電気自動車 is a 車
- ハット is a 帽子
- 中学校 is a 学校
と表せますね。
is-a の意味が難しいなら、日本語で 「~の一種」と考えてもいいです。
- 電気自動車 は 車 の一種
- ハット は 帽子 の一種
- 中学校 は 学校 の一種
ですね。
抽象クラスと具象クラスの関係は必ず is-a で表せなければなりません。
これが成り立たない場合、抽象クラスにはなり得ません。
抽象クラスをどう定義するかは、プログラムで解決したい課題によって変わります。
抽象化は現実的に正しいか正しくないかはそれほど重要ではなくて、今まさに書こうとしているプログラムの世界で整合性が取れていれば問題ありません。
上記の例で言うと、人間・猿・猫を哺乳類クラスとするか、動物クラスとするかは自由ですし、プログラミングで解決したい内容によって臨機応変に変える必要があります。
コーヒーブレイク
個人的に、オブジェクト指向設計は絵画を描くことに近いと思っています。
同じものを描いたとしても人によって表現の仕方は十人十色でしょう。
しかし見る人が見れば、明確に良い悪いはあります。
多くの人間が美しいと感じるものを表現できているかがポイントになると思います。
クラス設計で言えば、オブジェクトの役割が自然に想像できること。
シンプルさ(真理)を追い求めることが一つのヒントだと思っています。
インターフェースとは?
インターフェースとは概念的に 振る舞い を表すものです。
抽象クラスと対比して表すなら、同じものではないが同じ振る舞いをするグループという意味になります。
また、例を挙げてみましょう!
インターフェースの例
- 歩くことができる
- USBに接続することができる
- 支払うことができる
- 送信することができる
Javaなどで定義されているインターフェースの名称は、○○able という名前のことが多いですよね?
まさに上記の例のように、○○できる(グループ、機能、手段) みたいな感じで捉えると理解しやすくなります。
歩くことができるグループと表現すると、動物だけが対象ではなくなるのが分かるでしょう。
ロボットだって歩くことができればこのグループに入れることができます。
パソコンのUSB接続はインターフェースを概念的に理解する良い例だと思います。
USBに接続することができるデバイスは多岐に渡りますが、ユーザはUSBケーブルでどのような通信が行われているか知らなくてもデバイスを使うことができます。
USBの規格では、パソコンとUSBデバイスの通信プロトコルを抽象化しており、いずれのUSBデバイスもこの通信プロトコルのいずれかを実装しています。
インターフェースを使えば、同じ もの じゃなくても 同じ グループ にすることができるんですね。
(= 振る舞いが同じであれば、どんなものでもグループにすることができる)
振る舞いという概念を理解していれば、同じクラスに2つ以上の振る舞いを持っていても違和感がなくなるのが分かります。
人間クラスは、歩くことができるという特徴と、食べることができるという2つの特徴を持つと考えても違和感がないですよね?
これを、二足歩行動物クラス と 捕食生物クラス の2つを継承したと表現すると、動物と生物が混ざり合って訳が分からないことになりそうです。
人間クラスは、「歩くことができるインターフェース と 食べることができるインターフェース を両方実装したクラス」と定義した方が、
シンプルに振る舞いのみを抽出しているので、インターフェース同士の役割がぶつかりにくくスマートに表現しやすい場合が多いです。
ポイント解説
- なぜインターフェースを2つ以上実装する必要があるのか?
同じものを見たとしても、見る人が違えば違う振る舞いをするものに見える場合があります。
例えば、ある女性が居たとして、夫から見ればその女性は妻としての振る舞いを持っていますが、
学校の先生から見れば、○○君のお母さんとして見えるでしょう。
見る人によって同じクラスでも違う振る舞いをするものに見えるという事を表現するのがインターフェースの役割です。
そのクラスに二面性を持たせる、2つの特徴を持たせると理解してもいいです。
その結果、先生から見れば妻としての振る舞いに関与する必要がなくなり、クラス同士が疎結合になります。
疎結合にしていくことによって、後の実装変更の影響を受けにくい構造にすることができるのがオブジェクト指向のメリットになります。
結局どう使い分けるか?
共通的に扱いたいグループが、もの(Object)で分類することができる場合、抽象クラスにします。(必ず is-a関係になっていること)
それ以外の場合は、インターフェースにします。
使い分けることのメリット
抽象クラスはメソッドに処理を書くことができますが、もの で分類しているので共通処理を書いてもそのクラスの責任範囲が破綻しにくいです。
インターフェースでは、そのようなデフォルトメソッドを書いても概念的に合わなくなる場合が多いです。
こうした理由から、抽象クラスとインターフェースを概念的に理解して使い分けられれば、きれいなクラス設計になりやすくなります。
補足
インターフェースには、プロパティ・メンバ・フィールドと呼ばれる 属性 を持てません。
属性 が共通して無いものに対して、共通の処理を書こうとしても上手くいかないことが多いです。
属性 は違うが、同じ振る舞いをするのがインターフェースの本来の意味だからです。
まとめ
最後に、この記事の内容をまとめます。
要点まとめ
- 抽象クラスは もの を表す概念である
- インターフェースは 振る舞い を表す概念である
- 使い分けの方針は、もの で表せるなら抽象クラス、それ以外ならインターフェースとすればよい
- 抽象クラスとインターフェースを適切に使い分けることによりきれいなクラス設計になる
抽象クラスとインターフェースの違いについて、例を元に概念的なレベルでの解説をしました。
正直、初心者にとっては一度で理解するのは難しい内容もあるかと思います。
いずれオブジェクト指向学習のためのオススメの書籍なども紹介できればと思っています。
もし、この記事の内容について質問したいことや分かりにくい点などがありましたら、TwitterのDMやお問い合わせフォームから連絡を頂ければと思います。
記事に反映できるものがあれば改善して行きたいと思います。
最後まで読んでいただき、ありがとうございました。