図1●オブジェクトを組み合わせれば,効率的にシステムを開発できる<BR>オブジェクトの一つであるGUI部品を組み合わせて開発すれば,GUI部品がWindows APIを隠してくれるので,複雑なGUIであっても簡単に実装できる
図1●オブジェクトを組み合わせれば,効率的にシステムを開発できる<BR>オブジェクトの一つであるGUI部品を組み合わせて開発すれば,GUI部品がWindows APIを隠してくれるので,複雑なGUIであっても簡単に実装できる
[画像のクリックで拡大表示]
図2●大規模なプログラムもクラスでグループ化すれば効率的に開発できる&lt;BR&gt;関数や変数をまとめた“クラス”をプログラムの構成要素と考えれば,ソース・コードがグループ化されてプログラムが単純化できる。このことを設計時から考慮し,先にクラスを考え,後でクラス内の関数や変数を考えていく
図2●大規模なプログラムもクラスでグループ化すれば効率的に開発できる<BR>関数や変数をまとめた“クラス”をプログラムの構成要素と考えれば,ソース・コードがグループ化されてプログラムが単純化できる。このことを設計時から考慮し,先にクラスを考え,後でクラス内の関数や変数を考えていく
[画像のクリックで拡大表示]
図3●クラスとオブジェクトの違い&lt;BR&gt;クラスは実体を持たず,オブジェクトは実体を持つ。実体とは,メモリー上に確保される関数や変数のこと。オブジェクトがどんな関数や変数を持つのか,といったオブジェクトの“定義”を行っているのがクラスである
図3●クラスとオブジェクトの違い<BR>クラスは実体を持たず,オブジェクトは実体を持つ。実体とは,メモリー上に確保される関数や変数のこと。オブジェクトがどんな関数や変数を持つのか,といったオブジェクトの“定義”を行っているのがクラスである
[画像のクリックで拡大表示]
図4●オブジェクトの属性,操作,メッセージ&lt;BR&gt;属性,操作,メッセージとは,変数,関数,関数の呼び出しのこと
図4●オブジェクトの属性,操作,メッセージ<BR>属性,操作,メッセージとは,変数,関数,関数の呼び出しのこと
[画像のクリックで拡大表示]
図5●クラス間の包含関係と継承関係&lt;BR&gt;包含関係とは,クラスの内部にクラスがあるような関係。図上の電卓クラスと液晶画面クラス,ボタン・クラスの関係を指す。また,継承関係とは,クラスの属性や操作を引き継ぐような関係。図下の電卓クラスと関数電卓クラスの関係を指す
図5●クラス間の包含関係と継承関係<BR>包含関係とは,クラスの内部にクラスがあるような関係。図上の電卓クラスと液晶画面クラス,ボタン・クラスの関係を指す。また,継承関係とは,クラスの属性や操作を引き継ぐような関係。図下の電卓クラスと関数電卓クラスの関係を指す
[画像のクリックで拡大表示]
図6●クラスの共通点をまとめる“汎化”&lt;BR&gt;三角形クラスや四角形クラス,円クラスは,いずれも「色」という属性や「描画する」という操作を持つ。このような複数のクラスに共通する属性や操作をまとめて考えることを汎化という。汎化によって作られたクラスは,それぞれのクラスと継承関係にある
図6●クラスの共通点をまとめる“汎化”<BR>三角形クラスや四角形クラス,円クラスは,いずれも「色」という属性や「描画する」という操作を持つ。このような複数のクラスに共通する属性や操作をまとめて考えることを汎化という。汎化によって作られたクラスは,それぞれのクラスと継承関係にある
[画像のクリックで拡大表示]
図7●モデリングの基本的な手順&lt;BR&gt;クラスの属性や操作,クラス間の関連を決めることがモデリングである
図7●モデリングの基本的な手順<BR>クラスの属性や操作,クラス間の関連を決めることがモデリングである
[画像のクリックで拡大表示]
図8●カプセル化で属性を保護する&lt;BR&gt;カプセル化によって,クラスの属性を他クラスに見せず,クラスの操作を通してのみ値の変更が可能になる。こうしておけば,属性に不適切な値が設定されることは無い
図8●カプセル化で属性を保護する<BR>カプセル化によって,クラスの属性を他クラスに見せず,クラスの操作を通してのみ値の変更が可能になる。こうしておけば,属性に不適切な値が設定されることは無い
[画像のクリックで拡大表示]
図9●オブジェクト指向プログラミングの例&lt;BR&gt;クラスや継承,カプセル化,多態性などは,Java言語などのオブジェクト指向言語で実装することができる
図9●オブジェクト指向プログラミングの例<BR>クラスや継承,カプセル化,多態性などは,Java言語などのオブジェクト指向言語で実装することができる
[画像のクリックで拡大表示]

オブジェクト指向の基本

 オブジェクト指向とは,システムをオブジェクト(object=もの)の集合体としてとらえる考え方のことだ。システムの構成要素の中で,目に見えるハードウエアだけでなく,目に見えないソフトウエア(プログラム)もオブジェクトと考えるところが,オブジェクト指向の特徴である。

 オブジェクトは,システムの部品(コンポーネント)であるとも言える。ハードウエアもソフトウエアも部品化すれば,部品を組み合わせて効率的にシステムを開発できる。これは,自動車や家電品などの工業製品が,実際に部品を組み合わせて効率的に製造されていることと同じだ。

 皆さんのイメージを膨らませるために,オブジェクト指向でシステムを効率的に開発できる具体例を示そう。(図1[拡大表示])に示したWindowsアプリケーションは,ウインドウの土台となるフォーム,キー入力を受け取るテキスト・ボックス,マウス・クリックを受け取るボタンなどのオブジェクトを組み合わせて作成されている。これらのオブジェクトは,Visual Studioなどのプログラム開発ツールが提供する。言わば,市販品である。開発者は,市販のオブジェクトを組み合わせて効率的にシステムを作成したことになる。

 オブジェクトには市販品だけでなく,開発者が自ら作成するものもある。フォーム,テキスト・ボックス,ボタンなどのように画面に表示されるオブジェクトもあれば,内部ロジックを受け持つ非表示のオブジェクトもある。いずれの場合であっても,同じオブジェクトを他のシステムで再利用でき,オブジェクト単位での機能拡張が可能で,オブジェクト単位でメンテナンスを行えるというメリットがある。これらはいずれも,システム開発を大幅に効率化する。

オブジェクト指向の基本となる「クラス」

 オブジェクト指向に関する解説書は数多く存在し,その中にはあまたの技術が散りばめられているように思われるが,すべての基本となる技術が一つある。それは,「クラス」である。クラスが何であるかを理解することから始めよう。

 ソフトウエアすなわちプログラムが,命令とデータの集合体であることは,誰もが納得していただけるだろう。プログラミング用語で言えば,命令は関数,データは変数である。プログラマは,関数と変数に名前を付ける。1つのプログラムは,複数の関数と変数のセットとなり,それらは名前(関数名と変数名)で識別される。

 大規模なプログラムでは,その中に含まれる関数と変数の数が膨大なものとなる。それらをバラバラに放置していたのでは,管理が困難であり,開発効率が低下する。そこで,画面出力,演算処理,帳票出力など,管理しやすい単位で関数と変数をグループ化するアイデアが考案された。このグループのことをクラスと呼び,クラスに付けられた名前をクラス名と呼ぶ。大規模なプログラムであっても,クラスでグループ化すれば管理しやすくなり,効率的に開発できる(図2[拡大表示])。

 関数と変数がバラバラの状態になっているプログラムを,後からクラスでグループ化して整理するのでは,効率的とは言えない。プログラムを設計する段階で,先にグループを決め,後からグループに所属する関数と変数を取り決めていく方が効率的だ。するとどうだろう。これから作ろうとしているプログラムが,どのような部品(=クラス)から構成されているかを自然と考えるようになる。これこそ,オブジェクト指向の基本的な考え方である。

 現実世界の業務をプログラムに置き換える際に,クラスの集合体として設計することをモデリングと呼ぶ。これは,UMLのM(Modeling)である。モデリングという言葉から,飛行機などのプラモデルをイメージしてほしい。プラモデルは,実際の飛行機を構成する部品のセットになっている。プラモデルの部品は,プラモデルとして不要な機能が省略されている。このような部品化と省略化は,プログラムのモデリングでも同じだ。

クラスは定義で,その実体がオブジェクト

 クラスが基本となっていても,オブジェクト指向のことをクラス指向とは呼ばない。なぜなら,オブジェクト指向では,クラスとオブジェクトは,異なる概念として明確に区別されるからだ。

 ここでは,プラモデルではなく,プログラムをイメージしていただきたい。図1に示したWindowsアプリケーションをもう一度見てみよう。テキスト・ボックスとボタンという部品は,それぞれ2つずつ使われている。これをオブジェクト指向では,同じクラスのコピーが2つずつ作成されていると考える。このコピーのことをオブジェクト(またはインスタンス)と呼ぶ。

 プログラマが,関数と変数をグループにまとめてクラスを記述しただけでは,プログラムは動作しない。クラスは定義であって,実体ではないとみなされるからだ。プログラムの中に,クラスの実体すなわちオブジェクトを作成する処理を記述しなければ,クラスは機能しない*4

 なぜクラスとオブジェクトを分けて考えるのかと言えば,モデリングの対象となる現実世界がそうなっているからだ。例えば,何らかの業務システムで従業員というクラスを定義したとしよう。実際にプログラムが動作するときには,従業員の人数分のオブジェクトが作成される(図3[拡大表示])。

 オブジェクト指向では,「オブジェクトとは,属性と操作を持ち,メッセージを送り合うものである」と言われる。難しそうな表現だが,実際のプログラミングでは,属性は変数であり,操作(振る舞いとも呼ぶ)は関数である。メッセージとは,オブジェクトが他のオブジェクトの関数を呼び出すこと。実に簡単なことだ。

 従業員クラスを例に考えてみよう。従業員クラスの属性とは,氏名,生年月日,所属部門,役職などとなる。従業員クラスの操作は,電話に応対する,書類を書く,食事をするなどとなる。プログラムの実行時には,従業員クラスのオブジェクトが作成され,他のオブジェクトから何らかの操作が呼び出されることになる。これがメッセージである(図4[拡大表示])。

クラス間の関連には3つの種類がある

 プログラムを構成する個々のクラスやオブジェクトは,お互いに何らかの関連を持っている。関連には,3種類のスタイルがある。1つ目のスタイルは,クラスが他のクラスのオブジェクトを作成し,その操作を呼び出すことだ。2つ目のスタイルは,クラスが内部に他のクラスを含んでしまうことで,「包含」と呼ばれる。3つ目のスタイルは,既存のクラスを拡張して(属性と操作を引き継いで)新しいクラスを定義することで,「継承」と呼ばれる*5。どのスタイルを使うかは,モデリングにおいて自然と決定される。

 1つ目のスタイルは,メッセージを送るだけのことなので,すぐに理解できるだろう。包含と継承は,言葉だけを聞くと難しそうだが,現実世界と照らし合わせれば,イメージをつかめるはずだ。例えば電卓を思い浮かべてみよう。電卓は,液晶画面とボタンを包含している。電卓クラスが既に存在するなら,それを継承して(拡張して)関数電卓というクラスを定義できる*6図5[拡大表示])。

 継承は,モデリングの段階で「汎化」というスタイルで現れることもある。例えば,グラフィックスの描画を行うプログラムを設計し,三角形クラス,四角形クラス,円クラスという3つのクラスを定義したとしよう。これらのクラスには,どれも「図形の色」という属性と「描画する」という操作がある。同じ属性や操作が複数のクラスにあるのは,無駄なことである*7。そこで,3つのクラスに共通した属性と操作をまとめて図形クラスを新たに定義してみよう。これが汎化,すなわち共通部分をまとめることである。(図6[拡大表示])を見ると,設計時の考えは汎化だが,結果として,三角形クラス,四角形クラス,円クラスが,図形クラスを継承していることが分かる。共通点をまとめたクラスのことを「スーパークラス」と呼び,スーパークラスを継承するクラスを「サブクラス」と呼ぶことも覚えておこう。

 ここまでの説明を理解したなら,オブジェクト指向を採用したシステムの設計,すなわちモデリングが,どのような手順で行われるかをイメージできるだろう。

 モデリングの基本的な手順は,まず,(1)システム化の対象となる現実世界の業務の中に存在する部品を抽出し,それらに名前を付けてクラスとして定義する。次に,(2)個々のクラスが持つ属性と操作を決定し,最後に(3)クラス(オブジェクトも同様)間の関連を決定する(図7[拡大表示])。

 (1)クラスの抽出は,システムの仕様書の中にある名詞を抽出する作業となる。例えば,「液晶画面に8けたの演算結果を表示し,ボタン操作で四則演算が可能な電卓」という仕様の電卓システムなら,「液晶画面」,「ボタン」,「四則演算」,「電卓」などがクラスの候補だ。(2)属性や操作の決定は,例えば液晶画面クラスなら,「表示けた数」が属性で,「演算結果の表示」が操作となる。(3)では,電卓と液晶画面,および,電卓とボタンの間は包含関係にある,といったクラス間の関連を決める。

 図7に示した手順だけでは,システムの設計図が不完全だと思うだろう。その通りである。モデリングには,操作の内部的な処理手順を示すものがない。これは,プログラマがせっせとフロー・チャートを描いて設計することになる。

カプセル化でプログラマの混乱を抑える

 ここからは,オブジェクト指向の代表的な特性である「カプセル化」と「多態性」について説明する。

 カプセル化とは,クラスの持つ属性や操作の一部を外部に公開しないで隠すことである。公開することを「パブリック(public)」と呼び,公開しないことを「プライベート(private)」と呼ぶ。例えば,1万個の属性と2万個の操作を持つクラスを定義したとしよう。すべてをパブリックにしてしまったら,クラスを使う側のプログラマは,何を使ってよいのか分からず混乱してしまう。クラスを使う側にとって役に立つものだけをパブリックとし,その他はプライベートとすれば,分かりやすく効率的に開発が行える。

 カプセル化には,クラスの持つ属性に不適切な値が設定されないようにする目的もある。属性をプライベートとし,それを設定する操作をパブリックにするのだ。クラスを使う側からは,操作を呼び出すこと(すなわちメッセージを送ること)で間接的に属性を設定する。この操作の処理の中で,不適切な値が設定されないようにすれば良いのだ(図8[拡大表示])。

 多態性*とは,1つのクラスの中に,同じ名前で機能の異なる操作を複数定義することである。なぜ多態性が必要なのかと言えば,現実世界には同じ名前で機能の異なる操作が多々あるからだ。突拍子もない例えだが,紅白歌合戦の最後に北島三郎が登場し,その周りを鳩が飛び回ったとしよう。北島三郎は「トリ」であり,鳩も「トリ」だ。同じトリという名称で,歌う操作と飛ぶ操作を表す仕組みが多態性だ。とにかく,オブジェクト指向では,1つのクラスの中に同じ名前で機能の異なる操作を複数定義できることを覚えておいてほしい。

オブジェクト指向設計をプログラムで表す

 オブジェクト指向で設計されたシステムのプログラミングには,オブジェクト指向言語が使われる。現在主流となっているC++やJavaなどのプログラミング言語は,オブジェクト指向言語だ。米Microsoftが提供する新しいプログラミング言語であるC#や新しくなったVisual Basicもオブジェクト指向言語である。

 オブジェクト指向言語は,プログラムの言語構文としてクラスを定義でき,継承,カプセル化,多態性を実現できる。このセミナーはプログラミングがテーマではないが,皆さんのイメージを固めていただくために,Javaのプログラムの中でオブジェクト指向がどのように使われているかを簡単に示しておこう*8

 (図9[拡大表示])のリスト1は,myField属性とmyMethod()操作を持つMyClassクラスの定義である。public class MyClass{ ・・・ }が,クラスの範囲を示している。リスト2は,MyClassクラスを継承したNewClassクラスの定義である。NewClass extends MyClassの部分は,MyClassを継承してNewClassを定義するという意味だ。NewClassクラスには,newField属性とnewMethod()操作だけが定義されているが,MyClassクラスを継承しているので,myField属性とmyMethod()操作も持っているとみなされる。

 リスト3は,属性をカプセル化した例である。パブリックを表すpublicキーワードと,プライベートを表すprivateキーワードの使い分けに注目していただきたい。myFiled属性を間接的に設定するmyMethod()属性の処理として,これから設定されようとしている値をチェックし,それが「0」でないならmyFiled属性に設定している。

 リスト4は,多態性の例である。MyClassクラスには,整数型(int)を引数とするmyMethod()操作と,浮動小数点数型(double)を引数とする同じ名前のmyMethod()操作がある。Javaでは,操作の名前だけでなく,引数の数とデータ型や戻り値の型を含めて操作を識別することで,多態性を実現している。

 リスト5は,MyClassクラスのオブジェクトを作成し,myMethod()操作を呼び出している。Javaのみならず,多くのオブジェクト指向言語では,クラスをデータ型とした変数(ここではobj)を宣言し,=の右辺のnew演算子でクラスのコピーをメモリーにロードし,そのメモリー・アドレスを変数に代入するという構文で,オブジェクトを作成する。操作の呼び出しには,「アドレスを格納した変数名.操作名」という構文が使われる。

☆          ☆          ☆

 UMLは,これまでに説明したオブジェクト指向の考え方を図で表す方法である。UMLの図は,丸暗記して描けるようになるものではない。システムをオブジェクト指向で考え,モデリングするための便利な手段として,自然とUMLを使えるようにならなければ意味がない。次回は,UMLの9種類の図の描き方を一気に説明するので,今回の説明と照らし合わせていただきたい。


矢沢 久雄(やざわ ひさお)
1961年栃木県足利市生まれ。(株)ヤザワ取締役社長,グレープシティ(株)アドバイザリースタッフ。アプリケーションの開発・販売,プログラミングに関する書籍や雑誌記事の執筆,およびセミナーなどにおける講演活動を行っている。自称,ソフトウエア芸人。