こうすべき! オブジェクト指向プログラミング

商品コードとその数量』が複数あって、そのデータファイルを作るプログラム作成を考えます。
この場合、作ればよいだけなら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

staticメソッドで、staticが付かないフィールドを直接指定するとエラーです。

次の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);