改めてオブジェクト指向について考える

みるくあいらんどっ! > ドキュメント > Java > じっくり学ぶ Java講座 [初心者向け・入門]


インスタンスメソッドとオブジェクト指向

オブジェクト指向なソースコードが実現するかどうかは、インスタンスメソッドを上手く利用できるかどうかがひとつの大きな要素になります。以下では、生徒(Student)について、不完全なオブジェクト指向の例(staticなメソッド)とオブジェクト指向の例(インスタンスメソッド)について比較していきます。

仕様を以下に定めます。

  • 5人の生徒の名前と、英語、数学、理科の点数を格納する。
  • 点数の格納はコンストラクタで行う。ソースコード短縮のため、ゲッターのみ実装する(セッターは実装しない)。
  • それぞれの生徒について、各教科の点数と合計点・平均点を表示する。
  • 表示そのものはメインメソッドに実装する。
  • 見栄え重視のため平均点は整数とする。小数点以下は切り捨てる。

不完全なオブジェクト指向の例

staticなメソッドを用いて実装すると以下のようになります。

ソースコードは以下の通り。

K201/Student.java

/**
 * 生徒を表すクラスです。
 */
public class Student {
	/**
	 * 名前。
	 */
	private String name;
	/**
	 * 英語の点数。
	 */
	private int english;
	/**
	 * 数学の点数。
	 */
	private int math;
	/**
	 * 理科の点数。
	 */
	private int science;
	
	/**
	 * コンストラクタ。
	 * @param name 名前
	 */
	public Student(String name) {
		this(name, 0, 0, 0);
	}
	
	/**
	 * コンストラクタ。
	 * @param name 名前
	 * @param english 英語の点数
	 * @param math 数学の点数
	 * @param science 理科の点数
	 */
	public Student(String name, int english, int math, int science) {
		this.name = name;
		this.english = english;
		this.math = math;
		this.science = science;
	}
	
	/**
	 * 名前を返します。
	 * @return 名前
	 */
	public String getName() {
		return this.name;
	}
	
	/**
	 * 英語の点数を返します。
	 * @return 英語の点数
	 */
	public int getEnglish() {
		return this.english;
	}
	
	/**
	 * 数学の点数を返します。
	 * @return 数学の点数
	 */
	public int getMath() {
		return this.math;
	}
	
	/**
	 * 理科の点数を返します。
	 * @return 理科の点数
	 */
	public int getScience() {
		return this.science;
	}
	
}

K201/K201.java

/**
 * 生徒の点数と合計点、平均点を表示します。
 */
public class K201 {
	
	/**
	 * メインメソッド。
	 * @param args 引数
	 */
	public static void main(String[] args) {
		Student[] students = {
				new Student("山田", 85, 70, 60),
				new Student("田中", 50, 55, 75),
				new Student("鈴木", 70, 70, 65),
				new Student("佐藤", 40, 45, 85),
				new Student("小林", 80, 55, 90),
		};
		
		for(int i = 0; i < students.length; i ++) {
			System.out.print(students[i].getName() + "さんは");
			System.out.print("英語 " + students[i].getEnglish() + "点、");
			System.out.print("数学 " + students[i].getMath() + "点、");
			System.out.print("理科 " + students[i].getScience() + "点、");
			System.out.println();
			System.out.print("合計は " + K201.getSum(students[i]) + "点で、");
			System.out.print("平均は " + K201.getAverage(students[i]) + "点です。");
			System.out.println();
		}
	}
	
	/**
	 * 生徒の合計点を返します。
	 * @param student 生徒
	 * @return 合計点
	 */
	private static int getSum(Student student) {
		return student.getEnglish() + student.getMath() + student.getScience();
	}
	
	/**
	 * 生徒の平均点を返します。
	 * @param student 生徒
	 * @return 平均点
	 */
	private static int getAverage(Student student) {
		return K201.getSum(student) / 3;
	}
}

実行結果は以下の通り。

山田さんは英語 85点、数学 70点、理科 60点、
合計は 215点で、平均は 71点です。
田中さんは英語 50点、数学 55点、理科 75点、
合計は 180点で、平均は 60点です。
鈴木さんは英語 70点、数学 70点、理科 65点、
合計は 205点で、平均は 68点です。
佐藤さんは英語 40点、数学 45点、理科 85点、
合計は 170点で、平均は 56点です。
小林さんは英語 80点、数学 55点、理科 90点、
合計は 225点で、平均は 75点です。

まず、数を数えられることが大切です。Studentクラスについて、以下の数を正確に数えられるでしょうか。

  • Studentクラス
    • 宣言された staticなフィールド…0個
    • 宣言された staticなメソッド…0個
    • 宣言されたインスタンスフィールド…4個
    • 宣言されたインスタンスメソッド…4個
    • コンストラクタ…1種類

K201.javaの中に合計点を計算する staticなメソッド、平均点を計算する staticなメソッドがあります。また、それらのメソッドの最初の引数は Student型となっていることに注目してください。

オブジェクト指向の例

続いて、インスタンスメソッドとして合計点と平均点を計算することとします。

ソースコードは以下の通り。

K202/Student.java

/**
 * 生徒を表すクラスです。
 */
public class Student {
	/**
	 * 名前。
	 */
	private String name;
	/**
	 * 英語の点数。
	 */
	private int english;
	/**
	 * 数学の点数。
	 */
	private int math;
	/**
	 * 理科の点数。
	 */
	private int science;
	
	/**
	 * コンストラクタ。
	 * @param name 名前
	 */
	public Student(String name) {
		this(name, 0, 0, 0);
	}
	
	/**
	 * コンストラクタ。
	 * @param name 名前
	 * @param english 英語の点数
	 * @param math 数学の点数
	 * @param science 理科の点数
	 */
	public Student(String name, int english, int math, int science) {
		this.name = name;
		this.english = english;
		this.math = math;
		this.science = science;
	}
	
	/**
	 * 名前を返します。
	 * @return 名前
	 */
	public String getName() {
		return this.name;
	}
	
	/**
	 * 英語の点数を返します。
	 * @return 英語の点数
	 */
	public int getEnglish() {
		return this.english;
	}
	
	/**
	 * 数学の点数を返します。
	 * @return 数学の点数
	 */
	public int getMath() {
		return this.math;
	}
	
	/**
	 * 理科の点数を返します。
	 * @return 理科の点数
	 */
	public int getScience() {
		return this.science;
	}
	
	/**
	 * 合計点を返します。
	 * @return 合計点
	 */
	public int getSum() {
		return this.english + this.math + this.science;
	}
	
	/**
	 * 平均点を返します。
	 * @return 平均点
	 */
	public int getAverage() {
		return this.getSum() / 3;
	}
}

K202/K202.java

/**
 * 生徒の点数と合計点、平均点を表示します。
 */
public class K202 {
	
	/**
	 * メインメソッド。
	 * @param args 引数
	 */
	public static void main(String[] args) {
		Student[] students = {
				new Student("山田", 85, 70, 60),
				new Student("田中", 50, 55, 75),
				new Student("鈴木", 70, 70, 65),
				new Student("佐藤", 40, 45, 85),
				new Student("小林", 80, 55, 90),
		};
		
		for(int i = 0; i < students.length; i ++) {
			System.out.print(students[i].getName() + "さんは");
			System.out.print("英語 " + students[i].getEnglish() + "点、");
			System.out.print("数学 " + students[i].getMath() + "点、");
			System.out.print("理科 " + students[i].getScience() + "点、");
			System.out.println();
			System.out.print("合計は " + students[i].getSum() + "点で、");
			System.out.print("平均は " + students[i].getAverage() + "点です。");
			System.out.println();
		}
	}
	
}

実行結果は以下の通り。

山田さんは英語 85点、数学 70点、理科 60点、
合計は 215点で、平均は 71点です。
田中さんは英語 50点、数学 55点、理科 75点、
合計は 180点で、平均は 60点です。
鈴木さんは英語 70点、数学 70点、理科 65点、
合計は 205点で、平均は 68点です。
佐藤さんは英語 40点、数学 45点、理科 85点、
合計は 170点で、平均は 56点です。
小林さんは英語 80点、数学 55点、理科 90点、
合計は 225点で、平均は 75点です。

まず、数を数えられることが大切です。Studentクラスについて、以下の数を正確に数えられるでしょうか。

  • Studentクラス
    • 宣言された staticなフィールド…0個
    • 宣言された staticなメソッド…0個
    • 宣言されたインスタンスフィールド…4個
    • 宣言されたインスタンスメソッド…6個
    • コンストラクタ…1種類

両者の違いは些細に見えるかもしれません。しかし、これが大きな違いなのです。

非オブジェクト指向の言語では「(staticな)メソッドがデータを扱う」形でプログラムを記述しました。しかし、オブジェクト指向では「オブジェクトが(インスタンス)メソッドを持っている」という形に変化しました。主語がメソッドからオブジェクトに変わったのです。これはパラダイムシフトと呼べる変化だと思います。

最終更新: 2013/02/22 , 公開: 2013/02/19
▲top