Revised: Feb./20th/2003: Since: Dec./26th/2001
ここまでに、 Java の制御構造、基本ルールを説明しました。ココからは、ようやくオブジェクト指向の性質に付いて説明します。本稿の冒頭でオブジェクト指向の用語については既に紹介しましたが、ここでは別の説明をしてみます。
オブジェクト (object) とは、操作する「対象」のことです。更に詳しく言うなら、データとそれを処理する方法(メソッド)を一つのカプセルにしたものです。
オブジェクト指向 (oo: object oriented) とは、現実世界での作業の考え方をソフトウェア上で実現する設計思想のことです。オブジェクト指向では、オブジェクトというモノどうしが会話をして、これに基づいて各々が振舞うことで作業が進みます。
後続の章で、具体的なコードに基づいて、個々の概念についても説明します。ここでは、そんなものかなという概念を把握してください。
オブジェクト指向は、コーディングのスタイルから設計まで、広範な領域に渡る包括的な概念です。一言で説明するのは難しいので、ここではオブジェクト指向とそれ以外の差異を際立たせることで説明しましょう。
オブジェクト指向以前の言語は、 CPU の動作をプログラムに記述したものです。最初は CPU の動作を逐一、2進数で記述していました。これは機械語と呼ばれる言語です。機械語の二進数乃至は十六進数で記述された単語を、人間が理解できる単語(ニーモニック)に一対一に翻訳したのがアセンブリ言語と呼ばれるものです。それから、構文自体を人間が理解できる形に近づけた高級言語が生まれました。 FORTRAN, C, COBOL などがその代表です。これらは何れもコンピュータの動作を記述したプロシージャ指向言語(手続き型言語)です。
プロシージャ指向の言語では、コンピュータの制御の流れに注目して、プログラムを設計します。コンピュータ制御の流れを理路整然と記述するのがプログラムであり、データは断片的で、生成/消滅/変換を繰り返して処理が進みます。
プロシージャ指向のプログラミングは、構造化プログラミングと呼ばれる手法に洗練化されました。構造化プログラミングでは、データの流れ(データ・フロー)に注目してプログラムを設計します。プログラムのコードは、入力データを変換して出力する函のようなものです。このとき、データは変換されても消滅することはありません。どのデータがどこから入って、どのような変換を受けて、どんなデータがどこから出力されるのかと考えて設計します。
プロシージャ指向のプログラムでは、処理とデータは別のものとして分離しています。データは実行時にサブルーチン引数のような形で、プログラムの中で処理に渡され、処理によって変換を受けて、別の処理に渡されていきます。
オブジェクト指向は、データ・フロー中心主義を更に発展させたものです。オブジェクト指向では、プログラムは、データと振る舞いを一つにまとめたクラスの集合と考えて設計します。処理は、クラスから生成したオブジェクトたちが会話をすることで実現します。
そもそもは、実世界をコンピュータ内に写像するためのモデル化を意図して開発されました。実世界での作業のほとんどは、主観的に観ると、ボタンを押す、引っ張る、行き先を告げる、などのモノを相手にするものです。客観的に観ると、一連の作業は、たくさんのモノたちが協調して実現しています。モノたちは、別のモノから指示を受け取って、自身の役割に応じて振る舞い、結果を報告します。ここで言うモノがオブジェクトです。
オブジェクト指向のプログラムでは、処理とデータを一つにしたオブジェクトを扱います。オブジェクトは、他のオブジェクトとメッセージを交換することで振舞います。オブジェクト指向コンパイラは、データと処理を組み合わせてオブジェクトを生成するコードを生成します。実行環境はオブジェクトを生成し、オブジェクト間のメッセージの交換によってプログラムは動作します。
プロシージャ指向では、データと処理は分離しています。オブジェクト指向では、処理とデータを組み合わせたオブジェクトを扱います。
プロシージャ指向では、データが処理に渡されて変換を受けることがプログラムの実行であり、コンピュータ制御の流れを記述するものでした。データはコンピュータ制御が当該箇所から抜けると、メモリ上からドロップされるものです。オブジェクト指向では、実行時には、データと処理が一つになったオブジェクトが存在し、オブジェクト間でメッセージを交換することが、プログラムの実行になります。オブジェクトは、コンピュータ制御が当該オブジェクト内の処理から抜けても、メモリ上に存在し続け、継続的にアクセス可能です。つまり、コンパイラや、実行環境のメモリ管理など、実装レベルでプロシージャ指向とは異なっているのだということです。
プロシージャ指向でも、現代的には処理と処理対象データは組み合わせて設計するのですが、オブジェクト指向ではそれが言語仕様として実装されており、これが具体的な実装における最大の違いです。そして、コンパイラと実行環境の、このような実装の違いに基づいて、設計手法が変わり、分析手法が変わり、開発プロセスとその開発手法が異なってくるわけです。
概念的な説明が続きますが、特にプロシージャ指向からの移行を目的としている方は、もう少しお付き合いください。オブジェクト指向を理解するのには、コードを見て実際にコーディングすることも不可欠ですが、ソレに先立って概念を学ぶことにも意味があります。
開発においてオブジェクト指向の概念が重要なのは、単にコーディングするだけならば、オブジェクト指向コンパイラを使って、プロシージャ指向のプログラムを開発することも可能だからです。オブジェクトを生成するにしても、限りなくプロシージャ指向のプログラムを開発することもできます。このようなハイブリッドなプログラムは、コンピュータ制御が追いにくくなり、デバッグが困難で局所的な変更が大域的に影響を及ぼし、障害発生時にどこを直せばよいか分からないなどの邪悪な存在となります。
オブジェクト指向の概念を把握してからコーディングすることが肝要です。オブジェクト指向は、コーディングと設計の局面が融合し、分析と設計の境界も接近します。
オブジェクト指向の源流は SIMULA (1966-) であり、ほかには LOGO (1968-), Smalltalk (1972-) などが挙げられます。オブジェクト指向を取り入れた SIMULA と LOGO を融合させた Smalltalk は、O.J.ダールやアラン・ケイらによって XEROX の PARC 研究所で開発されました。 SIMULA のオブジェクト指向を洗練化させて市場に認知させた言語だそうです。実際、現代的なオブジェクト指向言語のほとんどは Smalltalk の確立したオブジェクト指向を取り入れています。SIMULA と C を融合させたという C++ は、市場で大成功を納めた言語ですが、純粋なオブジェクト指向言語ではなく、プロシージャ指向言語とのハイブリッド言語と呼ばれます。
Java は SIMULA, Smalltalk, C++ などの先行言語の「いいとこ取り」を目指した言語です。いままでみてきたとおり、 Java もまたオブジェクトを生成しないプログラミングが可能であり、純粋なオブジェクト指向言語ではありませんが、なかなかいい線行っていると思います。オブジェクトを生成しても、限りなくプロシージャ指向に作れるという点では、オブジェクト指向言語の完成形とも言われる Smalltalk であってもおなじことでしょう。オブジェクト指向は、従来のプログラミングだけではなく設計局面、更には分析やテスト局面まで巻き込んで完成する概念だからです。因みに、プロシージャ指向言語の最長老は FORTRAN (FORmula TRANslation) と COBOL (COmmon Busines Oriented Language)、完成形は C といわれています。これらは何れもコンパイラ型言語です。インタープリタ型言語の完成形は Perl といわれています。
最近の言語はみんなオブジェクト指向ですが、既存の言語もオブジェクトが使えるように修正されています。オブジェクト指向言語は百花繚乱、群雄割拠、玉石混交の状態です。こういうわけで、オブジェクトが使える言語を網羅することは不可能ですが、敢えて努めれば、以下のようなものが挙げられます。
他にも OOCOBOL (Object Oriented COBOL), CLOS (Common Lisp Object System), 一時話題になった Delphi など多くのものが挙げられます。そして新しい言語が生まれ続けています。当然、おまけでオブジェクト指向を付け加えただけのものから、"Born to be objective." なものまでピンキリです。うーん、Java は生き残れるんですかねぇ。
オブジェクト指向は、プログラミングだけでなく、設計手法、モデリング、開発プロセス全体に渡って取り入れられる包括的な概念となりました。
従来型の開発では、モデリングに DFD (Data Flow Diagram) を用い、開発プロセスにはウォーターフロー型が使われていました。要件の複雑化、ビジネス環境の急速な変化に対応するには、これらの方法では、手戻りなどのコストがかさむことになります。ウォーターフロー型は、開発プロセスを、分析、設計、開発、テストという局面に分割して、各局面間に明確な判定条件を設けて、局面間をまたぐ手戻りを許容しないプロセスです。このような開発プロセスでは、結果として、納期が遅くなり、コストがかさみ、要件を満足できるだけ実装できないクオリティの低い成果物しか出せないものとされています。
オブジェクト指向開発では、モデリングに UML (Unified Modeling Language) を用い、開発プロセスには反復型(イタラティブ型)を使います。反復型では、ウォーターフロー型で培った局面分割を複数回繰り返し、最初は分析、設計フェーズの比重を高くして、順次開発実施フェーズの比重を高めていき、最後はテスト・フェーズに偏重していくように作り込みを行うというものです。ワークフローを繰り返すたびに要件を取り込んで十分な実装を目指していくため、開発実施と設計の局面間の断絶はなくなり、設計と分析の間の距離も密接になります。特に、開発手法としては RUP (Rational Unified Procecc) が広く使われています。
反復型を更に高速化するものとして、 XP (eXtreme Programming) という開発手法に代表されるような、アジャイル型(俊敏型)の開発プロセスが使われ始めています。
オブジェクト指向プログラミングは、実行時のオブジェクトの動作を記述するものであって、設計の概念と非常に密接です。プロシージャ指向のウォーターフォール・プロセスのように、開発に先立って完全な設計を完成させることは困難であって、冗長性や工数の増大を抑えるためには、最初はミニマムの要件を実装し、順次拡大していく方法が馴染みます。設計局面と開発局面の間の明確な分離というものがありません。
・・・この文書中の「オブジェクト」、「オブジェクト指向」の登場頻度がめちゃめちゃ高いなぁ。なんか飽きてきましたね。でももう少し続きます。今度は、もう少しだけ具体的に、オブジェクト指向の用語説明です。
オブジェクト指向プログラミングでは、モノ(オブジェクト)という概念でアプリを捕らえます。モノ同士が「ソレをドウする」というメッセージのキャッチボールをすることで、全体の処理が進んでいくのです。
プログラムを特徴付けるのは、オブジェクトが含んでいるデータのことです。データはオブジェクトの属性であり、オブジェクトの状態を表現するものです。これは、具体的な数値のような生データであることもありますし、他のオブジェクトであることもあります。
オブジェクトは、そのデータを処理するロジックも含みます。このロジックのことをメソッドと呼びます。メソッドはオブジェクトを操作する方法であり、オブジェクトの振る舞いを記述するものです。オブジェクト間の会話は、メソッドを介して実行されます。オブジェクトのメソッドを知らないと、そのオブジェクトの使用方法/機能がわからないということなので、会話することができません。
オブジェクトとは、データとメソッドで構成されます。例えば、個人の預金口座をオブジェクトとして生成するならば、データには、口座名義、口座番号、預金残高、貸付高などが含まれるでしょう。メソッドには、預金する、引き出すなどが必要となるでしょう。このとき、メッセージは、「ソノ口座に、100円預金する」となります。「預金する」メソッドは、「預金残高をx円増やす」という処理を実行します。
オブジェクトは、クラスと呼ばれる鋳型から作られます。逆に言えば、オブジェクトはクラスという型を持っているのです。クラスは、変数とメソッドの集合であり、変数に具体的な値を代入して初期化することで、オブジェクトが生成されます。メモリ上のオブジェクトのデータをインスタンスと呼び、クラスを初期化してオブジェクトを生成することをインスタンス化と呼びます。
一つのクラスからは、複数のオブジェクトが生成され、各々のオブジェクトは別々のインスタンスを持ちます。例えば、同じ預金口座クラスから、菅井名義で初期化したオブジェクトと、川井名義で初期化したオブジェクトは別のものです。菅井名義のオブジェクトに「1千円を引き出す」というメッセージを送っても、川井名義のオブジェクトの「預金残高」データは変更を受けません。当たり前ですけどね。