LoginSignup
2
0

More than 3 years have passed since last update.

続:OOPのたとえ話が(略

Last updated at Posted at 2020-09-11

熱いぜ

以前にこんな記事を書いたのだが、久しぶりにOOPネタでトレンドが
炎上して 熱く燃えているではないか。そこで、あれからまた少し考え
を整理した結果として、自分の考える抽象クラスとインタフェースは
こんな感じ!という考え方を表明してみたい。あくまでも自分の考えは
こうだ、という表明である。思考はJava的で。
※コードはビルドしてないし概念提示用のためかなり適当です。

インタフェースとは

JavaのRunnableインタフェースがわかりやすいが、実装したい機能を表す
ハンドル(車のハンドルやバスケットの取手やドアノブのイメージ)だと
考えている。Runnableインタフェースで言うならば

  • スレッドとして実装したいメソッドを表現するインタフェース
  • スレッドの実装は要求ごとに異なるので好きに実装すればよい

という非常に便利な機能を提供してくれている。実装されているクラスが
何者かは知らなくても、インタフェースの機能は保証されると考えられる
ので、実装者はインタフェースを自由に実装できるし、使用者はメソッド
の機能にのみ着目して使える。

現実にこんな機能を実装することはあり得ないが、意味を表現する手段と
して車のハンドル、というインタフェースを考えてみる。

CarHandle.java
public interface CarHandle
{
    int turnRight(int angle); //実行後の角度を返す
    int turnLeft(int angle);
    void hold();
    void release(); //ハンドルから手を放し自然動作に任せる
}

CarHandleインタフェースは車のハンドル、という機能を表明している。
なので、実装先のConcreteオブジェクトがどんな車でもかまわない。
軽自動車、セダン、ワンボックスなど、オブジェクトの特性に合わせて
実装者がインタフェースの動作を実装すればよい。

また、実装先のConcreteオブジェクトが、CarHandleインタフェースを
実装したハンドルオブジェクトを受け取る、という形にするのもいい。
どんな特性のハンドルかは知らなくてもよいが、インタフェースが表明
する機能は実装されている。

CarHandleインタフェースを実装したメーカー純正ハンドルオブジェクト
とか、俺はカスタムするぜ!モモステオブジェクト!みたいな楽しいこと
ができてしまう。

では抽象クラス(abstract)って何だ?

これは一言で表現するなら、半完成品のキットパーツだと考えている。
例えばだ。私と同年代(と言えばピンときてしまう人はバラさないように)
の人は、自作PCに熱中した人もいるだろう。自分でケース、電源、マザー、
CPU、HDD、メモリモジュール、GPUをパーツ単位で買ってきて、自分好みの
性能やコストパフォーマンスのPCを組み立てて動かすのは、それだけでも
エキサイティングな遊びだった。

そして時は流れ、BTOメーカーが乱立する。Web上で注文内容を購入者の
好みにカスタマイズしたPCを完成品の形で届けてくれる。だがショップに
よってカスタムできる内容はまちまちで、理想スペックにはならないので
そのショップは選ばない、なんてこともあった。

さて(長い前置きだったが)半完成品でPCを売ってくれるBTOショップが
ついに現れた(と仮定しよう、実際にはそんなものはない)。購入者から
見て重要度の低いパーツ(ケースとかマザーとかHDDとか)はそこそこの
スペックを選択でき、重要なコアパーツ(CPU、GPU、メモリモジュール)
はダミーが乗っているPCを売ってくれるショップだ。当然キットパーツの
状態では動作しない(インスタンス化できない)。

だから購入者(実装者)がコアパーツを買ってきて(キットパーツクラス
を継承して)CPUはCore i9、GPUはGeForce RTX、メモリは8GBのDDR4を
4枚載せて32GBで、みたいなPCを作ることができる。

AbstractPC.java
public abstract class AbstractPC
{
    public int case()  //ケースはBTOで選ぶので実装済み
    {
        //ケースの処理だと思いねぇ
    }
    public int powerUnit() //電源はBTOで選ぶので実装済み
    {
        //電源の処理だと思いねぇ
    }
    public int motherBoard() //マザーはBTOで選ぶので実装済み
    {
        //マザーの処理だと思いねぇ
    }
    abstract int cpu(int model_no); //CPUは自分で買ってくる
    abstract int gpu(int model_no); //GPUは自分で買ってくる
    abstract int memory(int model_no, int nums); //RAMは自分で買ってくる
}

こいつを継承してCPU、GPU、メモリモジュールを買ってくる(実装する)
ことで、超コスパPCでもハイエンドPCでも作れてしまう。厳密には高性能
PCを作る場合は電源容量とかケースの排熱効率とか細かい話はあるのだが、
とりあえず考えないことにする。

Abstractクラスの利点・便利さという意味では、すでに固定化しており、
実装しても仕様変更の影響を受けにくいフレームワークの部分だけを実装
しておき、変化に対応したい処理は適応領域に合わせてカスタマイズした
実装をしたい、といった要求に応えられることだと思う。

正直なところ、インタフェースの便利さに比べると抽象クラスは使い所が
難しく、利用頻度は低いという印象を持っている。それでも部分実装済み
でコア部分だけを最適な実装にできる便利さには価値がある。

ところで・・・

もののついでにいろいろ検索しちゃったりしたのだが、典型的な進化論に
はまっちゃってる人とか割とゴロゴロしていて絶望を禁じ得ない。いやね、
進化論で説明したくなる気持ちはわかるよ。でもさ、犬とか猫みたいな、
何もサービスを提供してくれないオブジェクトを実装しても継承しても、
何が便利なのかさ~っぱりわからんのよ。作る意味が感じられない。

はっきり言うと「伝わらない」のだ。インタフェースだの抽象クラスだの
少々入り組んだ概念を説明するのに、プログラミングする自分が得られる
利益が何なのか伝わってこない。それではいかんと思うのだ。

だから、第三者に対してレクチャーする意図で説明するのなら、相手の立場で
「そうか、こんな便利なことができるんだ」という感動を生み出さなければ、
レクチャーとしては日本じゃあ二番目だ。感動は記憶に深く刻まれるのだ。

2
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0