いまだにオブジェクト指向とか言ってるのか、という話ですが、いまだに「プログラミングの勉強はじめました。オブジェクト指向が目標です!」みたいなのがThreadsに流れてきたりして、いつまでも無くならんなぁと思うわけですよ。
で、まあオブジェクト指向を勉強してしまいたくなるのは仕方がないとして、オブジェクト指向推しの本でのサンプルがだいたいヒドいのが問題だなと思ったわけです。
アプリケーションを見据えていない
オブジェクト指向の例として、自転車クラスだとか勇者クラスだとか定義するサンプルをみかけます。
自転車クラスを作る例の場合、車輪クラスがありサドルクラスがありペダルクラスがあり、ブレーキクラスはブレーキシュークラスやブレーキキャリパークラスを内包する、みたいなことをやりますね。JSONでやれ。
という感じで、単にJSONなど構造データのマッピングになりさがってたりします。
あと、現実の写像なんだ!とか言って、ペダルクラスに回転メソッドを呼び出すとチェーンクラスの動作メソッドが呼び出され後輪クラスの回転メソッドを呼び出す・・・いやチェーンクラスはチェーンジョイントの集まりで・・・とかやったりしますが、物理シミュレータでやれ。
いずれにせよ、どこまでも分解できたりして、楽しいけど意味のない作業になります。
結局それは、なんのアプリケーションで使うかという基準がなくやっているので、どうとでも好きにモデリングでき、そしてアプリケーションで使わないから意味がないってことになります。
アプリケーションを考えて自転車をモデリングしようとすると、資材管理なら部品クラスいっこあって、名前やらサイズやら価格やら入れば十分。物理シミュレーションなら必要なのは素材クラスで、剛体クラスだったり弾性体クラスだったりが欲しいけどパーツの意味とかは不要です。
PRGを作るといいながら勇者クラスや王様クラスを定義して、勇者クラスから王様クラスのtalkメソッドを呼び出すみたいな例を出している本もありますね。
インタフェースによる多重継承の例として姫インタフェースと勇者インタフェースを実装した姫勇者クラスを作ってたりもします。
けど、王様とか勇者とかはキャラクタの属性にするべきで、クラスとして表現するものではないです。
モデリングとしても、勇者は別の生き物かもしれないのでいいとして、姫なんて成長したら姫ではなくなるし没落したら剥奪されるし、クラスとしてあらわすのは不適切です。
あと、最初は勇者をクラスとしてるのに、姫勇者のところでインタフェースにしているけど、確かに多重継承はできるようになったけど今までの機能の実装は無理では、とつじつまがあわなくなっています。
これも、実際にRPGというアプリケーションを作ることなく、RPGにのせる部品だけを定義しようとしているから非現実的な例になっています。
結果として、オブジェクト指向機能をアプリケーション開発で実際にどう使っていいか全くわからないということになります。
言語機能は機能の実現のために用意されているわけで、そのサンプルはアプリケーションでの活用を見据えて、アプリケーション開発のどのようなシチュエーションでどのように使えるかを示す必要があると思います。
目的を規定せずにモデリングを考えても意味がない - きしだのHatena
実際のところ使いどころがない
これがなんで発生するかというと、「オブジェクト指向はすばらしい!」と書きながら、実際にオブジェクト指向がすばらしい例がなかなか見当たらないからですね。
実際のアプリケーションを見据えるとオブジェクト指向機能の使いどころがないんですよね。
アプリケーション全体にオブジェクト指向が使えるということを謳いながら、実際には単にデータ構造の定義だけになってしまいがち。実際、抽象データ型に継承を生やしたものがオブジェクト指向なので、メソッド付構造体としてデータ構造の定義に使うのが一番有用ということになります。そしてデータ分類にインタフェースをつかう。
ただ、そうすると「データ定義が便利なだけでは」となって「開発がとても素敵になります!」みたいなのとつじつまがあわなくなり、適当にアプリケーションっぽい空気を出しながら「大規模になったら便利なんです!小さいサンプルじゃわからないんです!」と誤魔化すことになります。
じゃあクラス継承は実際にどこで使うんだとなりますが、オブジェクト指向というのは状態管理技術なので、状態のあるところとなります。ただ、状態のあるところというのはアプリケーションの出入り口の入出力部分で、アプリケーションの中では状態を持たずステートレスになります。ということで、なかなかいい感じのサンプルができないということになります。
じゃあどんなサンプルがいいんだ?
「プロになるJava」では抽象データ型として定義したデータの分類と、テンプレートメソッドによる差分プログラミングを例として紹介しています。ただ、こちらはクラスの継承ではなくインタフェースで実現するべきで、そのように続けています。テンプレートメソッドは、ラムダによる実装に置き換えをします。
「プロになるJava」はアプリケーションを作ることを目標にしていて、クラスの継承はアプリケーション開発で当面必要になることがなくインタフェースを使うほうが多くの場合適切なので、インタフェースへ導いてる感じです。
クラスの継承である必要のある例としては、「WEB+DB PRESS Vol.132」の特集で、基底クラスにopen/closedのふたつの状態を持ち状態管理を行い、実際のopen/closeの実装は派生クラスで行うという例をあげています。
実際にだした例とはちょっと変えてますが、こんな感じ。
class Input {
boolean closed = true;
final void open() {
openImpl();
closed = false;
}
final void close() {
if (!closed) error;
closeImpl();
closed = true;
}
protected abstract openImpl();
protected abstract closeImpl();
}
オブジェクト指向は状態管理技術なので、状態管理を共通化し、状態遷移のトリガは個別に実装するという状況にハマります。
実際に、InputStreamを継承してFileInputStreamやSocketInputStreamを実装したり、DBConnectionを継承してMySQLConnectionやOracleConnectionを実装という場合にはクラス継承が便利です。
WEB+DB PRESSの例ではクラス継承が実際に便利な状況を示す必要があったので、このような例をあげました。
難点は、FileInputStreamやMySQLConnectionなどは世界にひとつだけ実装があればいいので、実装機会があまりないところ。
※ 追記
GUIコンポーネントは状態管理重要なので、オブジェクト指向がハマります。Windowsが流行ると同時にオブジェクト指向フィーバーが起きたのはそのせいですね。
ただ、GUIコンポーネントを作りましょうというのをサンプルにするのは結構大変。
あと、末端に状態管理するコンポーネント群があればいいので、アプリ側ではコンポーネント配置をHTMLやらXMLやら構造定義言語で定義して、関数的なイベントハンドラを登録でだいたいいけるようになっていますね。
※ 追記2
オブジェクト指向が継承で多態するプログラミングであるという話はこちらにまとめています。そうではないオブジェクト指向の定義があれば教えてください。
オブジェクト指向は継承で多態するプログラミング - きしだのHatena
※ 追記3
WEB+DB PRESS 132の内容はこんな感じ。みんな大好きいぬねこクラスの絵は残念ながら載せれていません。いぬねこ哺乳類クラスは「抽象クラスがなにか」という説明だけにはいいと思っています。
「オブジェクト指向神話からの脱却」という特集をWEB+DB PRESSで書きました - きしだのHatena
※ 追記4
アラン・ケイのオブジェクト指向は、基本的にコンセプトだけで実用化されていなくて、システム開発に適用できるようにした結果がアラン・ケイではないほうのオブジェクト指向だとおもいます。Smalltalkも普及のために手をいれたらC++と同じようなオブジェクト指向をされるようになっていて、アラン・ケイは自分の手を離れたと言ってます。
オブジェクトは小さいコンピュータであるべきと言ってることや、Erlangが元々のアイデアに近いと言ってることから、アイデアとして非同期通信モデルであるともいえるので、そうすると実用での出番は少なく、初心者向けプログラム入門書で出す必要性はないです。
まとめ
某Java本も まともなサンプルにしてくれー