図3 手続き指向とオブジェクト指向の違い
図3 手続き指向とオブジェクト指向の違い
[画像のクリックで拡大表示]
図4 オブジェクトとしての条件は,「カプセル化」と「メッセージ・パッシング」である<BR>カプセル化とはデータと処理(メソッド)を一体化して,他のオブジェクトからは直接データにアクセスさせないようにする仕組みを言う。メソッドを呼び出すためにオブジェクト同士が送受信する情報を「メッセージ」と呼び,この方式による連携手法を「メッセージ・パッシング」と呼ぶ
図4 オブジェクトとしての条件は,「カプセル化」と「メッセージ・パッシング」である<BR>カプセル化とはデータと処理(メソッド)を一体化して,他のオブジェクトからは直接データにアクセスさせないようにする仕組みを言う。メソッドを呼び出すためにオブジェクト同士が送受信する情報を「メッセージ」と呼び,この方式による連携手法を「メッセージ・パッシング」と呼ぶ
[画像のクリックで拡大表示]

“手続き型”に慣れるほど困難

 2つ目の難しさは,従来の手法に慣れたプログラマやエンジニアがオブジェクト指向を理解するには,180度異なる発想が必要になることだ。

 オブジェクト指向が登場する以前は,プロセサが行う1つひとつの作業,すなわち「手続き」を順に記述して,処理をこなしていく方式しかなかった。オブジェクト指向と対比する意味で,この方式を「手続き指向」と呼ぶ注2)。プログラミング言語で言えばCOBOLやCが相当する。

 実は,この手続き指向の“呪縛”がオブジェクト指向の理解を妨げている。NEC(NECソリューションズ)で教育事業を担当する西口敦子Eラーニング事業部主任は,オブジェクト指向を教える集合研修での印象をこう話す。「オブジェクト指向プログラミングの例題を解くときも,手続き指向の経験を積んでいる人は,手続き指向のプログラムが頭に浮かんでしまうようだ」。なまじ手続き指向が染みついているために,すぐに手続き指向でのプログラムが思い浮かんでしまい,オブジェクト指向への発想転換が難しいのである。

 以上のオブジェクト指向の2つの難しさに,思い当たることはなかっただろうか。まずはこれを自覚することが,オブジェクト指向を習得する第一歩だ。

難しいのは「当然すぎる」から

 では,これらの難しさをどのように乗り越えていけばいいのか。それには用語やテクニックにとらわれることなく,オブジェクト指向の根本的な考え方を理解することが肝心である。それができれば,様々な難解な概念もおのずと意味が分かり,実際のシステム構築の場面でも使いこなせるようになるはずだ。

 その意味で,ぜひ覚えるべき「大原則」がある。それは「オブジェクト指向は人間にとってごく自然な考えなのだ」ということである。自分にとって当たり前すぎることを改めて問いただされたら,答えに窮するのではないだろうか。

 オブジェクト指向が難しい理由は,オブジェクト指向が高度だからではない。オブジェクト指向とは,「ソフトウエアを人間にとって扱いやすいよう,現実の物事になぞらえて考える」手法である。手続き指向に慣れた,あるいは手続き指向のシステムを担当する多くのITエンジニアにとっては,このごく自然な考え方を理解することが,かえって難しい。

実は不自然だった手続き指向

 「でも,本当にオブジェクト指向は自然な考え方なのか?手続き指向で1つひとつ処理を記述していった方が,よっぽど簡単だし自然な気がするけど」。こう思う読者もいるだろう。そこで,まずは手続き指向がいかに人間にとって不自然な手法なのかを検討してみよう。

 手続き指向では,プログラムに対してデータを入力して何らかの処理を実行する。つまり,プログラム(処理)とデータを全く別物として扱う(図3[拡大表示])。

 これはプログラム上だけの話ではない。実際,コンピュータの中ではプログラムとデータを物理的に異なるメモリーに格納している。

 注目してほしいのは,コンピュータ内に存在しているデータは特別な意味を持たず,単なる数字の羅列に過ぎないことだ。例えば,コンピュータの中に「1000」というデータが存在するとしよう。すると,そのデータは,指定された処理(=プログラム)によって,「1000円」にも「1000個」にも意味を変える。

 ところが,現実の物事のあり方と照らし合わせてみると,コンピュータ流の方式は極めて不自然である。なぜなら,現実の世界には,「1000」という数値だけが存在することはあり得ない。普段はあまり意識したことはないだろうが,必ずデータには固有の意味がある。「1000円」,「1000個」,「1000km」,「1000人」…,といった具合だ。

昔は計算機の方が偉かった?

 ここで新たな疑問がわくかもしれない。「なぜコンピュータは,こんな方式でプログラムとデータを管理しているのだろう」。

 答えは簡単。コンピュータ内部の処理が手続き指向だからだ。コンピュータのプロセサは,メモリー上のプログラムを順番に読み込み,データを処理している。データにどんな意味があるかは全く関知していない。

 加えて,昔のコンピュータの処理性能は,今とは桁違いに低かった。例えば1970年代初頭に登場したIBMの超大型コンピュータ「システム/370」の性能は,現在のパソコンの数十~数百分の1に過ぎない。貧弱なコンピュータ資源を有効活用するには,コンピュータが最も処理しやすい形態,つまり手続き指向でプログラムを開発するしかなかった。

 人間にとっての分かりやすさ,使いやすさ,作りやすさよりも,コンピュータの資源を効率よく使うことが優先されたのである。その結果,1000というデータを,お金にも個数にも解釈できてしまう事態が起こった。

一体化すれば「意味」が決まる

 一方,前述したようにデータが固有の意味を持つということは,そのデータを使って実行できる処理も,必然的に決まる。例えば「1000円」を使ってできることは,「代金を支払う」とか「両替する」ことだ。“1000円と会話する”とか,“1000円を走る”,ということはない。これは,直感的に分かるだろう。

 オブジェクト指向とは,まさにこうした現実と同じような物事のありようを,ソフトウエアとして実現する考え方にほかならない。現実の機械部品を組み合わせるかのごとく,プログラムを組み合わせてシステムを開発することができれば,一から開発するよりはるかに効率的だ。

 では,どうすれば“モノのように扱える”ソフトを作れるのか。答えを言えば,「プログラム(処理)とデータをひとまとめにして」扱えばよい。具体的には,ひとまとめであることをプログラム上で記述する。同時に,データへアクセスすることのできる処理を限定するのである。

 「1000円」というデータを表現したいとしよう。このとき,1000というデータと,お金を処理するプログラムをひとまとめにする。これで,単なる数値に過ぎないデータに,固有の意味を与えるのだ。

 これがオブジェクト指向の解説書に当たり前のように出てくる「処理とデータの一体化」にほかならない。オブジェクト指向では処理を「メソッド」,データ項目を「属性注3)」と呼ぶ。メソッドと属性,そして属性の中身である具体的なデータを一体化させたもの,これが「オブジェクト」の正体だ(図3参照)。

「アクセス制限」が不可欠

 しかし一体化だけではまだ不十分である。いくら「データとメソッドを一体化してオブジェクトを作る」といっても,プログラマがその作法に従わなければ元も子もない。ソフトウエアは本質的に融通無碍(ゆうずうむげ)なものだ。やろうと思えば,データを直接参照したり変更したりと,自由にオブジェクトの内容を変えられてしまう。

 現実の世界では,こうした状況は起きない。例えば「タイガー・ウッズ」を考えてみよう。

 オブジェクト指向に沿って言えば,タイガー・ウッズという“オブジェクト”は「国籍」や「職業」といった属性を持ち,その具体的な値はそれぞれ「米国」と「プロゴルファー」となる。この属性に他人が“アクセス”して変更することは,言うまでもなく不可能だ。変更するには,ウッズに「映画俳優になってほしい」と頼むしかない。

 しかしソフトウエアとなると話は別だ。「タイガー・ウッズ」オブジェクト固有の属性を定義したとしても,勝手に属性を書き換えて,タイガー・ウッズを“日本人”や“プロ野球選手”に変えられてしまう。

 この事態を防止してオブジェクト指向の目的を達成するためには,オブジェクト内部への自由なアクセスを禁止しなければならない。そこで設けられたのが,入り口を制限して,オブジェクトが持つメソッドを呼び出す方式でのみアクセスできるようにする仕組みだ。

 ここでいう「入り口」とはアクセス専用のメソッド(インタフェース)のこと。このインタフェースを通してのみ,データを操作できるようにしている。このように,オブジェクト内部への自由なアクセスを制限することを「隠蔽」と言う。

 「一体化」と「隠蔽」。これこそがオブジェクト指向の基本をなす「カプセル化」である(図4[拡大表示])。

(鶴岡弘之,玉置亮太)