Step 3: オブジェクト指向ってなんだろう?
いやあ〜、ずいぶんと久しぶりだね!日本に帰ってきてからちょっと忙しかったし、なれない日本の生活に馴染むのに時間がかかってしまったの........(:_:)
アメリカに住む前は日本にいたんでしょ!でも、ほんとに久しぶりだね。もう、このまま終わっちゃうのかと思った。(いつも通りこの色はクマ好きの美樹ちゃんの言葉。)
ほっほっほっ、JDK (Java Development Kit) も Version 1.2 が正式にリリースされて Java
2 なんてプロジェクトに変わったしね。(最近、Sun は OS 環境も Solaris 2.7 じゃなくて Solaris 7
にしているよね)
今後のためにも、今回は「オブジェクト指向」について少し書くね。
わざわざ説明するってことはそんなに大切なの?
そうだね、実際には「オブジェクト指向プログラミング」というプログラミングスタイルを取り入れることが大切なんだ。 オブジェクトって物のことだよね。車やコンピュータ、ノートや鉛筆も物、つまりオブジェクトなんだよね。クマやネコ、人だってオブジェクトとして考えられるよね。
じゃあ、なぜそのオブジェクトをプログラミングに利用すると良いのかっていうと.....そうだなあ、美樹ちゃんは今まで主に C言語を使ってきたので、C言語と比較するとわかりやすいかな。
例えば、ロボット「タッチャン」の行動をプログラムする場合だけど、「タッチャン」を 100歩前進させるプログラムを書くとどうなるかな?(PlayStation
のゲームばかりしていて、言うこと聞かないってことはないからね!)
C言語のような手続き型言語では
int i; for ( i=0; i<100; i++) { タッチャンを前進させる処理を書く; }変数 i をもうけて i が 100 になるまでタッチャンを進ませるという手続きを書くプログラミングスタイルだよね。
Java のようなオブジェクト指向型言語では
Robot tacyan = new Robot(); tacyan.forward(100);
タッチャンというロボットオブジェクトを作成してそのロボットを 100歩進めるという風に書くんだ。
C言語の部分でも forward() という関数を作って引数に歩数を与えれば同じじゃないの?と思うかもしれないど、 C言語で書いたプログラムは他の人がソースをみても何かを
100前進させるってことは理解できてもそれが何かわからないよね。
forward(100);
その点、Java で書いた方は「ロボットであるタッチャンを 100歩進ませる」ということがソースコードから想像できるでしょ。
tacyan.forward(100);
このようにオブジェクト(この場合ロボット)を中心にプログラミングすることで、他の人にも理解しやすくなる、後で自分でソースを見直してもわかりやすいというのがオブジェクト指向プログラミングの重要なところの一つなんだ。
C 言語のような手続き型のプログラミングスタイルよりも人の考え方に近いプログラミングスタイルというのがわかるかな。
なぜこのような書き方が出来るのかというと、オブジェクト指向プログラミングの特徴の一つであるカプセル化(Encapsulation)を利用しているからなんだ。カプセル化って言うのは部品を作るようなものと思えばいいかな。forward
, back
, reft
, right
, jump
などの動作をもつ部品を作っておくと、部品を利用する人は 部品の機能 forward
の「右足を上げて前に出して下ろす。次に左足を上げて前に出して下ろす」という細かい意味を気にせずに、 部品の機能 forward
を使うだけでロボットを前進させることができる。 部品の機能 forward
の実際の処理を見せないように包み込んでいることもカプセル化の特徴です。自分で実際に歩くときも、右足上げて...なんて考えながら歩いていないでしょ。
このことがなぜ良いかというと、「近年優秀なプログラマーって減っている」「システムが複雑化してなかなか思うように開発が進まない」といった問題を解消できるからなんだ。コアの部分やいろいろな部品を優秀なプログラマーが提供して、他のプログラマーはその部品を利用してふだんの思考に近いスタイル(ブロックで物を組み立てるように)でプログラミングできる。そのことで、アプリケーション開発が楽になるっていうのが目的かな(昔、読んだオブジェクト指向の本には必ず書いてあったような覚えがあるなあ)。
みんなが使っているもので、もっとも代表的なものは
Window System (Windows, Macintosh ToolBox, X Window Widget, etc)。これらのプログラミングをするとき、ボタン、ウィンドウ、メニュー、スクロールバーなどはあらかじめ部品化されていて、プログラミングするときはそれらの部品を配置してアクション加えてラベルを変えるぐらいで使えるようになるでしょ。
あれ?でも、Window System の部品って C 言語とかで書かれていない?
そうだね、実際には手続き型の言語で実現されているけどオブジェクト指向風になるようなテクニックを使って実現されていることが多いんだ。ここでは、ブロックの組み立てみたいに使えるということが重要と理解してね。
この部品を作るときに、注意しなくてはいけないことがあるんだけれどどんなことだかわかる?
そうね。「部品として利用するならバグがあってはいけない!」「使いやすくないといけない!」
バグがあってはいけないのはどんなものでもそうだけど、使いやすくないといけないよね。そこが重要なんだよ。バグの話が出たのでちょっと横道にそれるけど、部品一つ一つが良くできていると、その部品を利用するとバグの無い製品が作りやすいよね。バグが出たとしても部品化されていることによってバグを発見しやすくもなる(特定の部品をチェックすればよいから)。
さて、注意することだけれど、使いやすさが重要だね!では、使いやすいものにするのはどうすれば良いでしょうか?
えーとね。わかりやすい名前を使う?
おしいなあ〜 わかりやすくしなくてはいけないのは名前だけではないんだよ!
「不必要な情報を隠して利用する際の混乱を少なくする」 --- 部品を利用するのに、あれして、こうして、ああやってから使うでは非常に使いづらい。forward
の例を取ると「歩数である 100」という引数以外利用する側からは見えないから簡単に使えるよね!このように、不必要な情報は表に出さないで隠すことを情報隠蔽っていうんだ。
「極力、単一機能の部品を作る」 --- 多機能な部品を作ると便利に見えるかもしれないけど、実際は使いづらいしバグを作りやすい。身の回りにある物を見ても部品一つ一つは単機能なのがわかるはずだよ。
情報隠蔽だけれど、会話を例に取るとどんな情報が行き交うことで物事が進むのか?必要な情報はなにでよけいな情報がなんなのかがわかるかな。例えば、喫茶店に行ってピザを頼む時に、ウェイトレスのお姉さんに「おなかが空いたので、僕のためにミックスピザを一つ作ってください」とは注文しないでしょ。その場の状況から、自分とウェイトレスのお姉さんとの間で注文のやりとりをするのは明白だし、自分の今の状態「おなかが空いた」をお姉さんに伝えなくても注文は成立する。「ミックスピザ一つ!」っていうだけで注文が成り立つよね。よく物事の説明で 5W1H (When, Where, Who, What, Why, How)って言うのがあるけど、わかっている情報をわざわざ再度教える必要はない。無用な情報を省くことで、簡潔に物事をすすめる(不必要な情報を隠す)。 このことが、部品を作る上でも必要だということだね。また、ピザを注文した後に、ウェイトレスのお姉さんに「当店のピザは新鮮な野菜を使い.........」などとピザの作り方なんて聞きたい訳じゃないので説明されても困るよね。自分の空腹感を癒してくれればいいわけだからピザをどういう方法で作ろうが関係ない。つまり、部品は目的を達成させることが重要で、どのように目的を達成させるかといった過程や手段は利用者には必要ない情報だということ(情報隠蔽)。
部品について説明したけど、部品を作っていくのはいいのだけれど、同じような機能なんだけど一部だけ違う機能をもったものが作りたい場合がでてくるよね。そんなとき、また一から部品を作っていくのは時間もコストもかかってもったいないよね。そこで、オブジェクト指向プログラミングでは、今ある部品を再利用して、異なる機能を追加する仕組みを提供しているんだ。その、再利用を可能にしたクラスと継承について説明しなくてはいけないな。
よし、美樹ちゃんだからクマを例に取るのがいいかな?
わーい! クマ くま 熊 . . .
はいはい。クマも一つのオブジェクトと判断できるので、クマ・オブジェクトとでもしようかな。
そこで、クマの性質を考えてみよう。クマはネコやイヌと同じように動物だけれど、クマだ!と認識できるのは、大きさや形だよね。また、冬眠するとか凶暴であるとかいったクマに共通の行動や状態をもっている。こうしたクマ特有の定義(状態や行動)をまとめたもの(抽象化:モデル化)をクマ・オブジェクトと区別してクマ・クラスと呼ぶんだ。
そうすると、クマやネコ、イヌは動物なので、動物の定義を動物・クラスと考えることができるよね。その動物の定義に大きさや形、冬眠する、凶暴などと新しい定義を加えるとクマ・クラス。さらに、色が白いと白クマ・クラス、胸に三日月の印があるとツキノワグマ・クラス、といった具合にまとめることができる。この抽象化された定義のことがクラス(class)と覚えてね。
なんか構造を持っているので、C 言語の構造体みたいだね!
そうだね、でも構造体と違うのは状態だけでなく行動といったふるまいを持っている。このふるまいを持っていることがオブジェクト指向プログラミングでは重要なんだ。それじゃあ、上の説明のクラスを図にしてみようね。
こんな感じかな。上の絵一つ一つがクラスとなるわけだね。そこで、クマ・クラスを見たときに上の動物クラスのことをスーパークラス(基本クラス)、下の白クマ・クラスやツキノワグマ・クラスをサブクラス(派生クラス)と言うんだ。このとき、サブクラス(白クマ・クラス)は上のクラス(クマ・クラス)から性質(クマである)を受け継ぐ、これを継承(Inheritance)と呼ぶ。白クマ・クラスから見るとクマ・クラスや動物クラスは、スーパークラスとなるんだからね。白クマ・クラスは、クマ・クラスを継承して色が白いと言う新しい定義を加えたものになるわけだ。この継承が、部品を再利用可能にしているんだ。
ここで、クマ・クラスや白クマ・クラスはクマである性質(状態やふるまい)を抽象化した定義(モデル)で実体では無い。動物園にいるクマのことではないんだ。そこで、○×動物園の額に傷のあるツキノワグマである「ゴン太」というのは、ツキノワグマ・クラスの実体化(インスタンシエイト)したものとなる。この実体のことをインスタンスというんだ。「抽象化されたクラス(定義)からインスタンス(実体)となってはじめてオブジェクトになる」
これまでのことをふまえてオブジェクト指向風に言い直すと、ツキノワグマ・クラスのインスタンスである「ゴン太」オブジェクトは、ツキノワグマの性質である胸に三日月という性質を持ち、冬眠をするなどといったクマの性質を継承している。さらに、実在する一匹のクマとして喧嘩で負った額の傷があるという固有の情報をもっているとなるんだ。(説明に竹岡さんの本を参考にさせていただきました。)
ちょっと、ロボット「タッチャン」をあてはめてみると、ロボット・クラスのインスタンスである「タッチャン」オブジェクトは、forward
というふるまい(手続きともいえるかな)をもっていることになる。このふるまいのことをメソッド(Method)と呼ぶんだ。オブジェクトは、このメソッドを実行することで処理が進んでいく。外側からオブジェクトに働きかけるには、オブジェクトにメッセージを送りつける(メッセージ伝達:Message
Passing )。メッセージを受け取ったオブジェクトは、対応するメソッドを起動して処理を行い、必要であれば結果をメッセージの送り元に返すといったことをする。「タッチャン」オブジェクトに、100歩前進しなさいとメッセージを送ると、「タッチャン」オブジェクトが持つ forward
メソッドが実行され、100歩も歩いたので疲れたとかメッセージが帰ってくるといった具合になる。 (C++ ではこのメソッドのことを、メンバー関数といっている)
継承を使うと、同じような機能を持つものは基本となるものを作ってから差分を作ればいいから開発時間も短縮できるでしょ。さらに、基本の部分はデバッグが済んでいるから差分をデバッグすればいいんだよ!
継承って便利でしょ。
そうねー 継承の機能を利用するだけでも開発時間が短縮できるね。
用語としてはもう少しあるんだけど、上の用語ぐらい覚えておけばだいたい大丈夫かな。 他の用語は、必要になったときにその都度説明するようにするね。
では、今回はこのぐらいで..........
次回は、ちゃんとあるのかな?また、数ヶ月経たないとダメかしら?
こらっ!次回は Java のキーワードについての説明するからね! (#-_-)