#OOで変更を容易にする「メッセージ」
意味が分かる「オブジェクト指向」入門 ――なぜOOなのか? - Qiita(前回)
前回からだいぶ時間が開いてしまって申し訳ないのですが、前回の内容を要約します。
前回、「オブジェクト指向(OO)」とは、変更を容易にするための技法だ、と説明しました。
今回、なぜ変更を容易にできるのか、どのようにすればできるのか、その代表的な原理を説明していきます。
具体的には「メッセージ」という仕組みを取り上げます。このような基本的な言葉の意味が分からないまま、オブジェクト指向を使いこなすのは難しいです。本連載ではこうした言葉の「意味」を再考していきます。
それでは、メッセージに込められたメッセージを読み解いていきましょう。
#メッセージの意味は何か?
「オブジェクト指向では、オブジェクトがメッセージを送り合う」といった記述を、読者のみなさんはすでに、OOの解説書や解説サイトで見たことがあるかもしれません。
よくある定番の説明なのですが、初見ではその深い意味はまず分からないと思います。そこで、この記事で意味を説明していきましょう。
ただし、この連載では「少数派の言葉の定義であっても、意味が分かりやすければ使う」というルールを採用することを断っておきます。
なぜそうするか。「メッセージ」という言葉を単なる「(手続き的)関数の呼び出し」と同じような意味で使っている場合が多数派でしょうが、それでは単なる言葉の言い換えで、意味がないからです。
単なる関数の呼び出しとは異なる意味で、メッセージを使う用法もあります。それを押しつけるわけではありませんが、意味ある少数派だからこそ、ご紹介しましょう。
#メソッドとメッセージ
JavaやRubyなどのオブジェクト指向言語では、オブジェクトが「メソッド」を持っています。手続き型言語であるC言語の関数などと違い、メソッドはクラスやオブジェクトに付属しています。これが関数とメソッドの違いです。
なお、このメソッドはJavaの用語で、C++では「メンバ関数」ですが、その違いはここでの問題ではありません。
本題に入りましょう。「メソッド」と区別してあえて「メッセージ」と呼ぶときに、他のオブジェクト(のメソッド)に送られるもの、という用法もあります。
慣れた用法を変えてしまうことに、どうしても抵抗があるならば、**たんなるメソッドの言い換えを「内部メッセージ」、他のオブジェクトへ送るものを「外部メッセージ」**などと、呼び分けても構いません。違いを考えるための便宜的な呼称だと捉えてください。
なぜ、わざわざ独自の言葉を使うかというと、たとえば**UMLの「シーケンス図」**を調べてみてください。これは基本的にオブジェクト間のメッセージを記載する図です。
手続き的な考え方からオブジェクト指向的な考え方へと変わっていく(オブ脳化する)ためには、考えのモデルが必要になります。たとえば、フローチャートからクラス図やシーケンス図へ、つまり制御構造からクラスやオブジェクト間の関係へ、切り替えていく必要があります。その一歩がオブジェクト内外の区別です。
ところで、「オブジェクトがメッセージを送り合というのはメルヘンの世界」などと揶揄されたりしますが、言葉の意味を深く理解すれば、メッセージがたんなる比喩でないことが分かってきます。
また、「OOが修正に強いというのはファンタジー」などと批判されたりしますが、OOを理解して組まないと、変更や修正に強くなりません。自動的に変更容易になるわけではありません。
原理原則を理解しなければ、たとえOOと何十年戦っても、表面的な機能を使っているだけに終わり、真に使いこなせるようにはなりません。
「メッセージ」というような表面的な用語を、知っているだけの人ならたくさんいます。が、原理に照らして意味が分かる、実際に役に立てて使える人となると、おそらくその数は激減するでしょう。
もっとも、OOの言葉の意味が分かるような解説が不足しているのが現状なので、仕様がない面もあります。しかしだからこそ、本連載を始めたわけです。
#メッセージは他者との応答
閑話休題。要点をまとめ直すと、他のオブジェクトのメソッドを呼び出すものが(外部)メッセージです。自分のオブジェクトだけでメソッドを使っている場合は、内部メッセージとここでは区別します。
これはたとえると、小説や演劇で言うならば、会話と独白の違いです。独白(OOで言うとレシーバがselfのメソッド)もできますが、「メッセージ」といえば、まず他人に対して送ることをイメージするでしょう。
この区別にどういう意味があるのかというと、それが「変更容易性」をもたらします。どういうことでしょうか?
「オブジェクト指向では、データと処理をオブジェクトに一体化」します。よくある説明なので、これも解説書などで見たことがあるかもしれません。
そこで、メッセージを送り合う、ということの裏を返すと、他のオブジェクトに送る(外部)メッセージでない場合、自分のオブジェクト内だけで処理できます。データはオブジェクトに一体化してあるので、外まで取りに行く必要がないのです。
だから、(外部)メッセージとそうでない場合を意識して使い分けることで、変更容易になるのです。
#メッセージを図解する
より理解を深めるために、あらためて、図で整理しましょう。
オブジェクト指向以前の「構造化」技法の時代は、関数(色の点)はありますが、オブジェクトという区別がありません。
オブジェクト指向では、メソッド(色の点)は、オブジェクト(黄色の丸い囲み)に属しています。他のオブジェクトとつながるメソッドが、メッセージ(緑の点)です。
ふたつの図を見くらべたときに、OOの方は黒い線が整理されています。後でもっと詳しくやるつもりですが、この状態を「疎結合」と言います。結合が疎、要はつながりが少ないわけです。
プログラムを直すときには、このつながり(黒い線)、つまり関数やメソッドのコール(とデータの参照)をたどる必要があります。これが多いと修正のときの影響範囲が広くなります。イメージとしては、「芋づる式」に直す必要がでてきます。これが変更を大変にする原因。そこで、つながりが少ないと、直しやすくなるというわけです。
一方で、オブジェクト単位でメソッドを分ける(黄色い線を引く)必要があるので、作成時の作業量が増えることがあります。しかし、変更しやすくなるので、「うさぎとかめ」の話のように、長期的にはコストを回収できます。
ただし、オブジェクト指向言語を使っていれば、自動的に変更容易になるわけではありません。オブジェクト指向的な分析、設計、つまり考え方が重要になります。これはOOPとOOADの違いと言われますが、今回はさしあたり「何が(外部)メッセージになるのか」ということに焦点を当てました。
#「求めるな、命じよ」
以上のことを、もう少し角度を変えて説明しましょう。オブジェクト指向の格言に「求めるな、命じよ」というものがあります。言い換えると、関数と(外部)メッセージは、命令と依頼の違いです。どういうことでしょうか?
たとえば学校で、生徒が教室に移動するとします。先生がひとりずつ行き先を説明するよりも、先生は「それでは各自移動してください」と言うだけで、生徒が自分で行き先を判断すれば、ずっと手間が少なくて済むでしょう。ただし、行き先を書いた紙をあらかじめ渡すなど、別の手間は生じます。
コンピュータが実行することを、一から十まで処理を命令するのが、命令型プログラミングだとすると、「一を聞いて十を知る」のが、オブジェクト指向プログラミングです。
あるクラスのオブジェクトに十個のメソッドがあって、そのうち一個が外部メッセージだとしましょう。外部からメッセージを送るだけで使えるようにすれば、外部から必要な操作が十分の一になります。組み上がるまでは大変ですが、出来てしまえば、依頼するだけの方がはるかに使いやすいのです。
さらに、工業製品を例にすると、想像しやすいでしょう。たとえば、自動車は内部にあるエンジンやギアに直接触れなくても、ハンドルとアクセル、ブレーキで操作できますね。あるいは、テレビ(モニタ)は、内部のブラウン管や液晶の仕組みを知らなくても、リモコンだけで操作できますね。
そこで、メッセージというのを、ボタンやリモコンで操作できることの延長で理解すると分かりやすい。要するに、ブラックボックスでも使えるということです。
自動販売機も、典型的なブラックボックスです。自販機内部の配線や、缶を送る機械を知らなくても、ボタンを押せば買えます。
自販機でジュースを買うことは、幼女でもできる。ボタンを押すだけで使いやすい。日常でこれは当たり前のことですが、コンピュータの世界は新分野なので、一昔前までは当たり前ではなかったのです。
オブジェクト指向の(外部)メッセージとは、このボタンのようなインターフェイスに相当すると解釈することもできます。インターフェイス以外は知らなくても使えるようにすると、使いやすくなります。
そこで、オブジェクト指向で組むときは、外部に対してメッセージを送っているかどうか、というオブジェクトの内外の区別が重要になります。
#「カプセル化」の意味
前回出てきた「カプセル化」は、「変更容易性」とともに、この連載でキーとなる概念です。「カプセル化」すると変更が容易になる、と説明しました。
今まで説明してきた、(外部)メッセージの仕組みも、カプセル化のひとつです。工業製品の内部を知らなくても操作できる、ブラックボックス化と似たような仕組みです。
というと、読者のみなさんは、違和感を覚えるかもしれません。カプセル化を情報隠蔽と同じ意味に捉えている方が多数派だと思います。具体的には、「private」をつけると外部からアクセスできない、というようなアクセス制御のことだと理解されているでしょう。
しかし、この連載で言う**「カプセル化」とは、「データの隠蔽」だけでない「あらゆる種類の隠蔽」**を意味します。
これは、前回も触れた『オブジェクト指向のこころ』や、他の書籍でもそういう用法があります。突然ここで勝手に決めたわけではないのです。
なぜ、少数派の定義を採用するのかといえば、その方が分かりやすいからです。オブジェクト指向を、カプセル化による変更容易化の仕組みと一元的に捉えることができます。
もちろん、「それだけが正当な解釈だ」などと押しつけるつもりはありませんが、オブジェクト指向の意味を分かりやすくするために、この連載ではそういう立場を取っていきます。
なお、これが「カプセル化」のすべてではありませんし、「メッセージ」のすべてではありません。しかし、ひとつの記事に新概念をたくさん詰め込むと分かりにくいので、以降の記事でも分散して少しずつ紹介していきます。