すがブロ

sugamasaoのhatenablogだよ

ガンダムでわかる interface と abstract

 仕事が暇なときに(ネットなどがないため)持参した Effective Java を読んでます。っていうか、忙しいようで中身は暇です。暇なのにホテル住まいとか逆にツラい。
で、 Effective Java の interface についての記事を読んでいたらふと思いついた。ガンダムを例にして interface と adstract の使い方についてうまいこと説明ができそうな気がしてきた*1
一応、注意しておくけどあんまりガンダムの歴史について突っ込まないでください。ある程度イメージで書いてるんで(笑)。


 まず、おさらいとして、それぞれがどういう文法的な使い方をするのか
■interface

  • implements で追加する
  • ひとつのクラスに複数の interface を追加できる
  • メソッドの実装はできない(定義はできる)

■abstract

  • extendsで継承する
  • ひとつしか追加できない*2Javaでは多重継承はできない)
  • メソッドの実装ができる

で、本題。
まずガンダムクラスがあると考える。
そして、ガンダムの後継機を開発しようとすると、ガンダムクラスを継承して新しいガンダムクラスを作成することになる。
この場合、以下のようになる。

ガンダム
↓【継承】
ガンダムmkII

ここで、陸戦型ガンダムを作ろう! となった場合(順序がめちゃくちゃだが気にしないでくれ)

ガンダム
↓【継承】
陸戦型ガンダム

これで陸戦型ガンダムは問題なく造れる。
じゃあ陸戦型ジムが欲しいときは?
 ここでこんなこと

陸戦型ガンダム
↓【継承】
陸戦型ジム

を考えちゃあいけない。機能的には十分実装できたとしても、だ。
あくまでガンダムはガンダム系であって、ジムはジム系なのだ。
だから、陸戦型ジムを考えるときはやはりジム系として、ジムクラスが必要になるだろう。

ジム
↓【継承】
陸戦型ジム

さあここで本当の本題だ。
陸戦型ガンダムと陸戦型ジムはほとんど同じ機能を持っている。
違いはガンダム系かジム系かという点だけ。
この場合、陸戦型ガンダムと陸戦型ジムをスマートに実装するにはどうしたら良いだろうか?
陸戦型ガンダムと陸戦型ジムで共通の機能を考えれば「陸戦型」として共通の機能リストを作成できる。
こうすることで、同じ機能の設計を二つ作る(≠実装)ということはしなくてすむ。
これで実装するとこんな感じになるだろう。

ガンダム
↓【継承】
陸戦型ガンダム←【interface】陸戦型

ジム ↓【継承】 陸戦型ジム←【interface】陸戦型

これのナニがいいのか? 手間が増えただけじゃないのか? と思うだろう。
けど、本当に言いたいことはここじゃないんだ。この先。
ガンダムもジムも陸戦用に改造する根本のところはそれぞれ違う場合がある(ネジとか鉄板の大きさとか)けど、共通の機能を設計をすることで装備(バズーカなど)に対する互換性が持ちやすくなるわけ。メンテナンスもしやすくなるよね。

 じゃあ、abstractでやるとどうなの? 「陸戦型」を実装できるし便利じゃん。
……果たしてどうだろうか。以下を見てもらいたい。

陸戦型
↓【abstractな陸戦型クラスを継承】
陸戦型ガンダム

陸戦型 ↓【abstractな陸戦型クラスを継承】 陸戦型ジム

 あれ、おかしいな。確かに「陸戦型」をまとめることはできたけど、ガンダムやジムの系統がぶった切れたぞ??
これは意味が違ってくるよね。
「陸戦型」という機能に着目して新しいモビルスーツを造ろうというのならば、それは新しい系統のモビルスーツになってしまう。
これでなんとなく雰囲気は伝わっただろうか。
いままでのをまとめるとこんな感じ。


■interface:新しい機能を既存のクラスなどに「追加」するときに使う
 →陸用や宇宙用など、系統ではなく横断的な機能*3を付ける時に使う
■adstract:これが無いと困る! という機能をクラスに持たせるために使う。
 →ガンダムっぽい顔とか(笑)、この系統として必要な機能を付ける時に使う

 以上、でガンダムでわかる〜は終わり。あんまり推敲しないで書いたんだけどあっているだろうか。不安でたまらん。。。

*1:初心者にとってこの二つは実にわかりにくい存在だ

*2:クラスだから当たり前だけど

*3:いわゆるmixinってヤツ