ぺぷしのーげん

大企業からスタートアップに転職したアプリケーションエンジニアのブログ

抽象クラス(Abstract)とインターフェース(Interface)の違いと使い分けについて|オブジェクト指向のススメ[C#][Java]

f:id:hazakurakeita:20160809014716p:plain

オブジェクト指向型言語に出てくる抽象クラスとインターフェースという概念。教科書ではほとんど同じにしか見えない両者ですが、今回はその違いと使い分けについて書いてみます。

 

コード的な違い

  • インターフェースは実装を持てないが、抽象クラスは実装を持つことができる
  • 具象クラスはインターフェースを複数実装できるが、抽象クラスは1つしか継承することができない

教科書的には上記が主な違いになると思います。先生やテストで聞かれても上記を書けば点数はもらえますよね。でも、これを知っているだけでは何の役にも立ちません。使い分けできませんから。結局上記の違いから使い分けるという残念なコードを生むことになります。

  • 複数の具象クラスで利用したいからインターフェースにしよう
  • 処理を共通化したいから抽象クラス使おう

これはコードの品質を下げる思考です。オブジェクト指向ではありません。

 

では何が違うのか

オブジェクトとして役割が違います。

  • 抽象クラス: 複数の概念から抽象化されたオブジェクト
  • インターフェース: オブジェクトに機能を与えるもの

文章で説明するの難しいですが、僕の頭を整理する意味も込めて文章化してみます。

抽象クラス

複数の概念から抽象化されたオブジェクトというのは、複数の概念に存在する共通のバックグラウンド・概念を定義するということです。決して共通の機能を取り出すわけではありません。例えば自動車で例えてみましょう。

f:id:hazakurakeita:20160809012622p:plain

これはトヨタ自動車プリウスのクラス図です。抽象クラスPriusを継承しているのは各世代のプリウスの型式です。今までプリウスには大きく4つの世代と、各マイナーチェンジの兄弟がいます。それらの型式の一部です。ここで、抽象クラスと具象クラスには「ほとんど同じ」という関係になっています。しかし、プリウスという自動車は厳密には存在しません。世代によってデザインは全く異なります。その違いを具象クラスが定義しているのです。決して全世代のプリウスの共通機能を集約したものがプリウスではありません。そんな作り方をしていると、新たな世代のプリウスが作れなくなります。残念ながら多くのエンジニアはそういう作り方をしているので、仕様変更や機能拡張に多くの時間を必要としてしまいます。

f:id:hazakurakeita:20160809013114p:plain

抽象クラスと具象クラスがほとんど同じということは、Carという抽象クラスからPriusの具象クラスの間には相当の数の抽象クラスが存在することになります。が、多くの教科書にはCarクラスをPriusクラスが継承している絵が描かれています。これは間違いです。あまりにも差が大きすぎます。Carクラスを継承している他のクラスにテスラの電気自動車や、マツダのクリーンディーゼル車も並んでいます。こんな抽象クラスはあり得ません。これでは万能クラスです。いずれメンテナンスできなくなり破綻します。

インターフェース

インターフェースはオブジェクトに機能を与えるものです。オブジェクトとして異なるもの同士でも同じ機能を有している場合は同じインターフェースのインスタンスとして扱うことができるというものです。抽象クラスとは全然違います。こちらも自動車で例えてみましょう。

f:id:hazakurakeita:20160809013429p:plain

 IMoterDrivenはモーター駆動機能のインターフェースです。このインターフェースを実装しているのはトヨタ自動車のPriusクラスやテスラモータースのモデルS、日産自動車リーフがあります。先ほどの抽象クラスではこれらのクラスを1つのスーパークラスで汎化することはできませんでしたが、インターフェースなら可能です。なぜなら、これらの自動車は全てモーター駆動の機能を有しているためです。これらの自動車は、1つのモーター駆動インスタンスとしてモーター駆動に関する動作を表現することができます。このように、インターフェースの場合はオブジェクト的に似ている必要は必ずしもないのです。

 

まとめ

以上のとこから、抽象クラスはオブジェクトとしてモデル化されたものであり、インターフェースはオブジェクトに機能を与える存在であることが分かります。あくまで抽象クラスやインターフェースを先に設計し、書くべきで、先に書いた具象クラスから抽象クラスやインターフェースを考えたり生み出したりしてはいけません。先に出した抽象クラスやインターフェースを1つの自動車モデルにまとめると下のようになります。

f:id:hazakurakeita:20160809014434p:plain

これもまだまだですが、設計の第一段階はいかに抽象クラスやインターフェースに対して実装を書くかが大切です。これを癖にしてから次のステップに進みたいですねー。しかしオブジェクト指向が強くなればなるほどクラスやファイルが増えますねー。必然的にクラス図などの資料がないと開発に支障がでます。その件はまた後ほど。

 

 

おしまい。