Part3では,オブジェクト指向の重要な要素の一つである「カプセル化」について学びます。カプセル化は,クラス内の変数やメソッドへの外部からのアクセスを制御する手法です。そのために使うのが「private」修飾子です。

 Par2では,Java言語でクラスを作る方法を学びました。しかし,クラスを作っただけではオブジェクト指向のプログラムと呼べません。プログラムを複数のクラスに分割するだけでなく,それぞれのクラスが,オブジェクト指向のクラスを正しく表現できているかどうかが重要な点です。そこでPart3では,カプセル化という手法を使ってクラスを作成する方法を紹介します。

関数を再利用しやすくする 構造化プログラミング

 カプセル化は,クラス内の変数やメソッドへの外部からのアクセスを制御する手法です。カプセル化したオブジェクトは,ほかのオブジェクトから影響を受けにくく,安全に扱うことができます。

 そもそもカプセル化という概念のルーツは,構造化プログラミングにあります。そこでまず,構造化プログラミングの話から始めたいと思います。構造化プログラミングは,簡単な処理の組み合わせとして複雑な処理を構成することにより,プログラムの見通しを良くする手法です。その結果,プログラムのバグが減り,メンテナンスや再利用がしやすくなるという利点があります。

 構造化プログラミングに使用する言語として代表的なものにC言語が挙げられます。C言語のプログラミングでは,最も小さな処理単位を関数として作ります。最も小さな処理単位なので,一つひとつの関数はできる限り単純な構造にします。そして複数の関数を呼び出す別の関数を作り,さらにこれらの関数をモジュールという単位でまとめていくことで,複雑な処理を行うアプリケーションへと作り上げていくのです。

 構造化プログラミングに基づいてアプリケーションを開発すると,繰り返し行う処理が見えてきます。例えば,ドライブやフォルダを選択してファイルを選ぶ処理や,印刷処理などです。こうした処理はほかのアプリケーションでも同じように使うので,再利用することを前提にして関数やモジュールを設計します。このような手法を,プログラムの部品化と呼びます。再利用しやすいプログラム部品がいくつもあると,開発効率が大きく向上します。

 プログラムを部品化する際には,注意すべき点が一つあります。それは,ほかのモジュールからの独立性を高くすることです。独立性が低いモジュールは,それだけを切り出して使うことが難しいので,再利用には向きません。

 構造化プログラミングでモジュールの独立性を低くしてしまう要因の一つにグローバル変数があります。グローバル変数は,プログラム中のどのモジュール(関数)からでも参照できる変数のことです(図1)。複数の関数で同じデータを使うときに共有領域として使用できますから,使いようによっては便利な仕組みです。

図1●グローバル変数を使うとデータを簡単に共有できるが,関数同士の独立性が低くなる
図1●グローバル変数を使うとデータを簡単に共有できるが,関数同士の独立性が低くなる

 しかし,どの関数からも自由に参照できるということは,グローバル変数を通じて関数同士に強い依存関係が生じることを意味します。例えばある関数で,ほかの関数がグローバル変数に代入した値を使っている場合,その関数だけを取り出して再利用することが難しくなります。そのため構造化プログラミングでは,部品化(独立性)を考慮して,グローバル変数は,原則として使わない決まりになっています。

 グローバル変数を使わずにデータの受け渡しをするには,関数の引数と戻り値を使用します。引数はその関数の中だけで有効なローカル変数ですから,関数の外から変更できません。戻り値も値を返すだけなので関数に影響を及ぼしません。引数と戻り値を利用すれば,関数の独立性が高くなり,再利用しやすくなります。

ローカル変数の値はメソッドを 呼び出すたびに初期化される

 オブジェクト指向プログラミングでも部品単位の再利用は重要です。Java言語の場合,C言語の関数がメソッドに,モジュールがクラスに相当します。皆さんがJava言語を習得して実際に仕事で使うとなると,チームで開発することが多くなるでしょう。その場合,クラスを再利用する局面が多くなりますから,再利用を支援する機能について理解しておくことは必須と言えます。

 クラスの再利用を支援する機能の一つがカプセル化です。カプセル化は,構造化プログラミングにおける「どこからでも自由にアクセスできる変数(グローバル変数)は使わない」という考え方をオブジェクト指向プログラミングに取り入れたものです。関数やモジュールの独立性を高めるためにどこからでも自由にアクセスできる変数を使わないのと同じように,オブジェクト内の変数への不用意なアクセスを禁止するわけです。

 Java言語で「個人」を表すクラスを作りながら考えてみましょう。個人というオブジェクトには,名前,年齢,国籍や住所など様々な属性が考えられます。とりあえずPerson1クラスに年齢を表示するprintAgeメソッドを宣言,定義してみます(リスト1)。

class Person1 {
  void printAge() {
    System.out.print(38);
  }
}
リスト1●年齢を表示するメソッドを備えたクラス

 printAgeメソッドを外部のクラスから利用する場合,インスタンス化して呼び出します。リスト2のTest1クラスは,printAgeメソッドを利用して年齢を表示します。

リスト2●リスト1のクラスを利用して年齢を表示させるクラス
リスト2●リスト1のクラスを利用して年齢を表示させるクラス

 3行目でPerson1クラスをインスタンス化し,5行目でprintAgeメソッドを呼び出しています。プログラムの内容を理解できたら,コンパイルして実行してみましょう(図2)。

図2●リスト1,リスト2をコンパイル,実行したところ
図2●リスト1,リスト2をコンパイル,実行したところ