『商品コードとその数量』が複数あって、そのデータファイルを作るプログラム作成を考えます。
この場合、作ればよいだけならmain一つの中で、指定のファイルを作成して、指定のデータを順番に書きこんでしまえば終わりです。
しかし、このような簡単な場合でも『如何にしたら将来、再利用できるか?』の視点で、
将来的な処理を検討すると、『商品コードとその数量』の「ファイル内データ集計作業」があるかも、
「複数のファイルで集計」するかも、
「特定範囲のデータを抽出」する作業があるかも、
または「並び替えする」必要があるかも、
『商品コードとその数』に新しく商品名などの「項目を追加」しなくてはならなくなるかも、・・・
と可能性がある処理はたくさん挙げられます。それらを考慮して、再利用できるように、プログラムすることです。
さて、『商品コードとその数量』という単位で、命令を分割していくと再利用しやすいことが想像できます。
『画面表示』、『データ設定』、『ファイル書き込み』『ファイル読み込み』、・・などの命令を、
一つの『商品コードとその数量』の情報に対する命令として作れば、
前述で列挙した「複数のファイルで集計」、「特定範囲のデータを抽出」・・でも利用できそうという訳です。
ここでは、『画面表示』、『データ設定』のメソッドを作成します。
C言語などで使われるグローバル関数との違いを知るために、次のクラスを示します。 staticを使うことで、昔から使われるサブルーチンに対する引数渡しの作り方ができます。 オブジェクトに対するメソッドの作り方の比較です。
public class Record2{ public String sho; // 商品コード public short suu; // 数量 //n番目表示としてオペレータ用で画面表示する(C言語流の作り方) public static void display(Record2 rec, int n){ System.out.printf("%4d番目レコード\n", n); System.out.printf("\t商品コード:%s\n", rec.sho); System.out.printf("\t数量:%d\n", rec.suu); } //n番目表示としてオペレータ用で画面表示する(オブジェクト指向の作り方) public void display(int n){ System.out.printf("%4d番目レコード\n", n); System.out.printf("\t商品コード:%s\n", sho); System.out.printf("\t数量:%d\n", suu); } }
以下で、この2つのメソッドを比較します。(機能的には同じです。)
public class Test{ public static void main(String[] arg){ Record2 a = new Record2(); a.sho = "A01"; a.suu = 10; Record2.display(a, 1);//C言語のグローバル関数的な使い方 a.display( 1 );//オブジェクトに対して実行するメソッドの使い方 } }
2つのdisplayの作り方は、どちらも間違ってはいません。
しかし、グローバル関数的な方の使い方では、命令と情報の関係が明確に見えません。
例えば Record2.display(a, 1)は、aと1の情報で表示させる命令です。
ここで、aが表示したい情報で、1は付随するものという関係ですが、この逆(1をaの付随情報で表示)にも見えます。
この関係を明確にするために、オブジェクト指向言語では、
『aを、付随情報で表示させる』を、『a.display( 付随情報 )』のような表記にしました。
そしてこの場合のdisplayは、aというオブジェクトに対する命令ということで、
そのオブジェクトの設計書(クラス)内で定義する規則になったのです。
そして、staticが付かないメソッドでは、a.display( 付随情報 )の中で、aの情報(フィールド)を
アクセスするできるようにしたわけです。
public class Record2{ public String sho; // 商品コード public short suu; // 数量 //n番目表示としてオペレータ用で画面表示する public void display(int n){ System.out.printf("%4d番目レコード\n", n); System.out.printf("\t商品コード:%s\n", sho);// a.display( 1 )のa.shoを意味します。 System.out.printf("\t数量:%d\n", suu);// a.display( 1 )のa.suuを意味します } }
なお、上記 Testクラスの実行画面は、以下のようになります
1番目レコード 商品コード:A01 数量:10 1番目レコード 商品コード:A01 数量:10
次のsuuように書くとコンパイルエラーです。それは、オブジェクトが指定されていないからです。
public class Record2 { public String sho; // 商品コード public short suu; // 数量 //n番目表示としてオペレータ用で画面表示する public static void display(Record2 rec, int n){ System.out.printf("%4d番目レコード\n", n); System.out.printf("\t商品コード:%s\n", rec.sho); System.out.printf("\t数量:%d\n", suu); } }
static でない 変数 suu を static コンテキストから参照することはできません。
上記エラーメッセージの「コンテキスト」とは『処理対象を判断する時に使っているもの』を意味するコンピュータ 用語です。contextの直訳は「文脈」です。コンパイラの言語処理において、文法となる規則の構造が「文脈」 となるわけですが、この例ではsuuを、コンパイラが判断する過程で、現在のstatic displayメソッドから利用できないのでエラーといっているのです。 つまり、この場合の「コンテキスト」は、displayメソッドを指しています。
ページ冒頭で説明したとおり、Record2のクラスが将来的に色々な使われ方があると想定される時、
オブジェクトの内部(フィールド)を設定するためのメソッドを用意した方が使いやすくなります。
そのメソッド名には、initなど、initializeの初期化を意味する名前がよく用いられます。
以下にそのinitメソッドを追加した例と、その利用例を示します。
public class Record2{ public String sho; // 商品コード public short suu; // 数量 //n番目表示としてオペレータ用で画面表示する public void display(int n){ System.out.printf("%4d番目レコード\n", n); System.out.printf("\t商品コード:%s\n", sho); System.out.printf("\t数量:%d\n", suu); } //商品コードと数量を引数で設定するメソッド public void init(String shoCode, int n) { sho = shoCode; suu = (short)n; } }
使えば、Record2オブジェクトを管理(参照)している変数aがある時、
a.sho = "A01";
a.suu = 10;
と書いていたものを、上記initメソッドがあれば、次のように簡単に書けます。
a.init("A01", 10);