12 プログラムの構造化(1)(メソッド・引数)

12.1 学習目標

12.2 メソッド

12.2.1 メソッドとは

メソッドとは、処理のまとまりのことです。 処理をまとめ、メソッド化することで、

というメリットがあります。

12.2.2 四角形を描くプログラム

以下のプログラムは、メソッドを使って四角形を描くプログラムです。

リスト 12.2.2.1 DrawRectangleMethod.java
  1: /*
  2:  * 例題1:四角形を描くプログラム
  3:  * (メソッドの作り方の練習)
  4:  * 作成者:MegumiAraki
  5:  * 作成日:2007/06/09
  6:  * メールアドレス:garnet@sfc.keio.ac.jp
  7:  */
  8: 
  9: public class DrawRectangleMethod extends Turtle {
 10: 
 11: 	//起動処理
 12: 	public static void main(String[] args) {
 13: 		Turtle.startTurtle(new DrawRectangleMethod());
 14: 	}
 15: 
 16: 	//タートルを動かす処理
 17: 	public void start() {
 18: 		
 19: 		drawRectangle();// 四角形を描く処理を呼び出す
 20: 
 21: 	}
 22: 
 23: 	//四角形を描く
 24: 	void drawRectangle(){
 25: 		for (int i = 0; i < 4; i++) {
 26: 			fd(50);
 27: 			rt(90);
 28: 		}
 29: 	}
 30: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

while文とfor文

このプログラムでは、繰り返しをfor文を使って書いています。for文を使うと、while文よりも短く書くことができます。

for文の()の中の命令は、それぞれwhile文と以下のように対応しています。

図 62 while文とfor文

i=i+1とi++は、いずれもiに1を足す、という意味です。while文でi++と書くことも、for文でi=i+1と書くこともできます。

12.2.3 メソッドの作り方

12.2.3.1 メソッド定義とメソッド呼び出し

メソッドを使うためには、メソッドを定義し、そのメソッドを呼び出す必要があります。

メソッドは一度定義すれば、同じメソッドを何度も呼び出して使うことができます。

このプログラムでは24行目でメソッドを定義し、19行目で呼び出しています。

						
24: void drawRectangle(){ 
25: 	for (int i = 0; i < 4;i++) { 
26: 		fd(50); 
27: 		rt(90); 
28: 	} 
29: }

					
19: drawRectangle();// 四角形を描く処理を呼び出す
					

引数・戻り値なしのメソッド定義、メソッド呼び出しの一般形は以下の通りです

void [メソッド名](){

}

					
[メソッド名]();

12.2.3.2 メソッド定義の注意点

次のプログラムは、四角形を描くプログラムを書こうとして、失敗した例です。

リスト 12.2.3.2.1 DrawRectangleMethodError.java
  1: /*
  2: * 四角形を描くプログラム(コンパイルエラー)
  3: * (メソッド定義の間違い)
  4: * 作成者:MegumiAraki
  5: * 作成日:2007/06/09
  6: * メールアドレス:garnet@sfc.keio.ac.jp
  7: */
  8: 
  9: public class DrawRectangleMethodError extends Turtle {
 10: 	
 11: 	//起動処理
 12: 	public static void main(String[] args) {
 13: 		Turtle.startTurtle(new DrawRectangleMethodError());
 14: 	}
 15: 	
 16: 	//タートルを動かす処理
 17: 	public void start() {
 18: 		
 19: 		drawRectangle();// 四角形を描く処理を呼び出す
 20: 
 21: 		//四角形を描く
 22: 		void drawRectangle(){
 23: 			for (int i = 0; i < 4; i++) {
 24: 				fd(50);
 25: 				rt(90);
 26: 			}
 27: 		}
 28: 
 29: 	}
 30: }

このプログラムを実行しようとすると、以下のようなエラーが出ます。

DrawRectangleMethodError.java:22: 式の開始が不正です。
		void drawRectangle(){
		^
DrawRectangleMethodError.java:22: ';' がありません。
		void drawRectangle(){
		                  ^
エラー 2 個

					

これは、メソッドの中にメソッドを定義しているためです。 このプログラムでは、startメソッドの中に、drawRectangleメソッドを定義しています。

図 12.2.3.2.1 メソッド定義のミス

Javaでは、メソッドの中にメソッドを定義することはできません。( 2章「プログラムの要素」参照 ) メソッドは、クラスブロックの中に書く必要があります。 正しいメソッド定義は以下のとおりです。

図 12.2.3.2.2 正しいメソッド定義

12.2.4 四角形を3つ描くプログラム

以下のプログラムは、四角形を描くメソッドを使って、四角形を3つ描くプログラムです。

リスト 12.2.4.1 DrawThreeRectanglesMethod.java
  1: /*
  2:  * 例題2:四角形を3つ描くプログラム
  3:  * (メソッド処理の順序)
  4:  * 作成者:MegumiAraki
  5:  * 作成日:2007/06/09
  6:  * メールアドレス:garnet@sfc.keio.ac.jp
  7:  */
  8: 
  9: public class DrawThreeRectanglesMethod extends Turtle {
 10: 
 11: 	//起動処理
 12: 	public static void main(String[] args) {
 13: 		Turtle.startTurtle(new DrawThreeRectanglesMethod());
 14: 	}
 15: 
 16: 	//タートルを動かす処理
 17: 	public void start() {
 18: 		
 19: 		//四角形を3つ描く
 20: 		for(int i=0; i<3;i++){
 21: 			drawRectangle();//四角形を描く
 22: 			move();//次の描く位置まで移動する
 23: 		}
 24: 
 25: 	}
 26: 
 27: 	//四角形を描く
 28: 	void drawRectangle(){
 29: 		for (int i = 0; i < 4; i++) {
 30: 			fd(50);
 31: 			rt(90);
 32: 		}
 33: 	}
 34: 	
 35: 	//次の描く位置まで移動する
 36: 	void move(){
 37: 		up();
 38: 		rt(90);
 39: 		fd(60);
 40: 		lt(90);
 41: 		down();
 42: 	}
 43: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

12.2.5 メソッドの処理の順序

メソッドが呼び出されると、プログラムの処理はそのメソッドの処理に飛びます。 そして、メソッドが終了すると、メソッド呼び出し位置に返ってきます。

図 12.2.5.1 メソッドの処理の順序

四角形を3つ描くプログラムでは、まず、四角形を描くメソッドを呼び、 四角形を描き終わったら、次の描く位置まで移動するメソッドを呼び、 移動し終わったら、再び四角形を描くメソッドを呼び…という処理を3回繰り返しています。

やってみよう!

上向きの三角形を描くメソッド【drawTriangle()】を作りましょう。

(はじめ、亀は上を向いていて、三角形を描き終わった後も、上向きに戻るものとします)

やってみよう!

三角形を描くメソッドと四角形を描くメソッドを使い、家を描くメソッド【DrawHouse()】を作りましょう。

12.3 引数ありメソッド

12.3.1 引数とは

メソッドブロック内で宣言された変数は、メソッドブロック内でしか有効ではありません。 しかし、あるメソッドから他のメソッドを呼ぶときに、データを受け渡したいことがあります。 引数とは、メソッドブロック外と、メソッドブロック内でデータをやり取りする仕組みです。 引数を使うことで、メソッドブロック外から、メソッドブロック内にデータを受け取ることができます。

12.3.2 大きさを変えて四角形を描くプログラム(コンパイルエラー)

次のプログラムは、一辺の長さを指定して四角形を描くプログラムを書こうとして、失敗した例です。

リスト 12.3.2.1 DrawVariableRectangleMethodError.java
  1: /*
  2:  * 四角形を描くプログラム(コンパイルエラー)
  3:  * (引数ありメソッドの練習)
  4:  * 作成者:MegumiAraki
  5:  * 作成日:2007/06/09
  6:  * メールアドレス:garnet@sfc.keio.ac.jp
  7:  */
  8: 
  9: public class DrawVariableRectangleMethodError extends Turtle {
 10: 
 11: 	//起動処理
 12: 	public static void main(String[] args) {
 13: 		Turtle.startTurtle(new DrawVariableRectangleMethodError());
 14: 	}
 15: 	
 16: 	//タートルを動かす処理
 17: 	void start() {
 18: 
 19: 		// 一辺の長さの入力を受け取る
 20: 		int length = 0;
 21: 		print("一辺の長さを入力してください");
 22: 		length = input();
 23: 		
 24: 		drawRectangle();// 一辺の長さを指定して四角形を描く
 25: 
 26: 	}
 27: 
 28: 	//四角形を描く
 29: 	void drawRectangle(){
 30: 		for (int i = 0; i < 4; i++) {
 31: 			fd(length);
 32: 			rt(90);
 33: 		}
 34: 	}
 35: }

12.3.3 変数の有効範囲(復習)

大きさを変えて四角形を描くプログラム(コンパイルエラー)を実行しようとすると、以下のようなエラーが出ます

					
DrawRectangleMethodError.java:31: シンボルを見つけられません。
シンボル: 変数 length 
場所 : DrawRectangleMethodError の クラス
					fd(length);

				

fd(length)のlengthという変数が見つけられないということを意味しています。

これは、drawRectangle()メソッドの内部({と}で囲われた部分)が、lengthという変数の有効範囲外であるためです。

図 12.3.3.1 変数の有効範囲

12.3.4 大きさを変えて四角形を描くプログラム

以下のプログラムは、引数を使って、メソッドの有効範囲外から四角形の長さを渡せるようにしたプログラムです。

入力された長さ(実引数)を、メソッドにlength(仮引数)として渡し、四角形を描いています。

リスト 12.3.4.1 DrawVariableRectangleMethod.java
  1: /*
  2:  * 四角形を描くプログラム
  3:  * (引数ありメソッドの練習)
  4:  * 作成者:MegumiAraki
  5:  * 作成日:2007/06/09
  6:  * メールアドレス:garnet@sfc.keio.ac.jp
  7:  */
  8: 
  9: public class DrawVariableRectangleMethod extends Turtle {
 10: 
 11: 	//起動処理
 12: 	public static void main(String[] args) {
 13: 		Turtle.startTurtle(new DrawVariableRectangleMethod());
 14: 	}
 15: 	
 16: 	//タートルを動かす処理
 17: 	void start() {
 18: 
 19: 		// 一辺の長さの入力を受け取る
 20: 		int inputLength = 0;
 21: 		print("一辺の長さを入力してください");
 22: 		inputLength = input();
 23: 		
 24: 		drawRectangle(inputLength);// 入力された長さを一辺の長さとして四角形を描く
 25: 
 26: 	}
 27: 
 28: 	//四角形を描く
 29: 	void drawRectangle(int length){
 30: 		for (int i = 0; i < 4; i++) {
 31: 			fd(length);
 32: 			rt(90);
 33: 		}
 34: 	}
 35: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

12.3.5 引数ありメソッドの宣言と呼び出し

引数ありメソッドを使うためには、引数ありメソッドを宣言し、そのメソッドを引数つきで呼び出す必要があります。

このプログラムでは29行目でメソッドを定義し、24行目で呼び出しています。

					
29: void drawRectangle(int length){ 
30: 	for (int i =0; i < 4; i++) { 
31: 		fd(length); 
32: 		rt(90); 
33: 	}
34: }

				
24: drawRectangle(inputLength);//入力された長さを一辺の長さとして四角形を描く

				

このプログラムメソッドを呼び出す際にinputLengthという変数を実引数として渡していますが、 drawRectangle(50)やdrawRectangle(100)などのように、実際の値を実引数として渡すこともできます。

引数・戻り値なしのメソッド定義、メソッド呼び出しの一般形は以下の通りです

呼び出し部分の引数を実引数、宣言部分の引数を仮引数と呼びます。実引数(メソッドブロック外にあるデータ)が、 仮引数(メソッドブロック内で使える変数)に代入され、メソッドブロック内で使えるようになります。

					
void [メソッド名]([引数の型] [仮引数名]){

}

				
[メソッド名]([実引数]);
やってみよう!

家を描くメソッド【DrawHouse()】を改良し、大きさを変えられる家を描くメソッド【DrawHouse(int size)】を作りましょう。

12.4 メソッドを用いたプログラムの構造化

ここでは、以下のような構造を持った「窓付きの家を描くプログラム」を例に、プログラムの構造化について説明します。

「窓付きの家を描く」処理は、1レベル下の、「屋根を描く」「壁を描く」「窓を描く」処理の3つの処理で成り立っています。

「屋根を描く」処理はさらに1レベル下の、「三角形を描く」という処理で、「壁を描く」処理は「四角形を描く」処理で、 「窓を描く」処理は「窓を描く位置に移動する」という処理と「小さな四角形を描く」処理で成り立っています。

図 12.4.1 窓付きの家を描くプログラムの構造

12.4.1 窓付きの家を描くプログラム(メソッドなし)

次のプログラムは窓付きの家を描くプログラムです。このプログラムではメソッドを使っていません。

リスト 12.4.1.1 House01.java
  1: /*
  2: * 窓付きの家を描くプログラム(メソッドなし)
  3: * 作成者:MegumiAraki
  4: * 作成日:2007/06/09
  5: * メールアドレス:garnet@sfc.keio.ac.jp
  6: */
  7: 
  8: public class House01 extends Turtle {
  9: 	
 10: 	//起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new House01());
 13: 	}
 14: 	
 15: 	// 家を描く
 16: 	//タートルを動かす処理
 17: 	public void start() {
 18: 		
 19: 		// 屋根を描く
 20: 		// 向きを調節する
 21: 		rt(30);
 22: 		// 三角形を描く
 23: 		for (int i = 0; i < 3; i++) {
 24: 			fd(80);
 25: 			rt(120);
 26: 		}
 27: 		// 向きを上向きに戻す
 28: 		lt(30);
 29: 		
 30: 		// 壁を描く
 31: 		rt(90); // 向きを調節する
 32: 		// 四角形を描く
 33: 		for (int j= 0; j < 4; j++) {
 34: 			fd(80);
 35: 			rt(90);
 36: 		}
 37: 		lt(90);// 向きを上向きに戻す
 38: 		
 39: 		// 窓を描く位置まで移動する
 40: 		// 前処理
 41: 		up();
 42: 		// 右へ22
 43: 		rt(90);
 44: 		fd(22);
 45: 		// 下へ22
 46: 		rt(90);
 47: 		fd(22);
 48: 		// 後処理
 49: 		rt(180);
 50: 		down();
 51: 		
 52: 		// 窓を描く
 53: 		rt(90);//向きを調節する
 54: 		for (int i = 0; i < 4; i++) {
 55: 			//小さな四角形を描く
 56: 			for (int j= 0; j < 4; j++) {
 57: 				fd(16);
 58: 				rt(90);
 59: 			}
 60: 			fd(16 * 2 + 4);
 61: 			rt(90);
 62: 		}
 63: 		lt(90);//向きを上向きに戻す
 64: 	}
 65: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

12.4.2 窓付きの家を描くプログラム(1レベルをメソッド化)

次のプログラムでは、「窓付きの家を描く」処理は「屋根を描く」「壁を描く」「窓を描く」処理の3つの処理で成り立っていると考え、 「屋根を描く」「壁を描く」「窓を描く」メソッドを作成しました。

リスト 12.4.2.1 House02.java
  1: /*
  2: * 窓付きの家を描くプログラム(1レベルをメソッド化)
  3: * 作成者:MegumiAraki
  4: * 作成日:2007/06/09
  5: * メールアドレス:garnet@sfc.keio.ac.jp
  6: */
  7: public class House02 extends Turtle {
  8: 	
  9: 	//起動処理
 10: 	public static void main(String[] args) {
 11: 		Turtle.startTurtle(new House02());
 12: 	}
 13: 	
 14: 	// 家を描く
 15: 	//タートルを動かす処理
 16: 	public void start() {
 17: 		drawRoof(); // 屋根を描く
 18: 		drawWall(); // 壁を描く
 19: 		drawWindow(); // 窓を描く
 20: 	}
 21: 	
 22: 	// 屋根を描く
 23: 	void drawRoof() {
 24: 		//三角形を描く
 25: 		// 向きを調節する
 26: 		rt(30);
 27: 		
 28: 		// 三角形を描く
 29: 		for (int i = 0; i < 3; i++) {
 30: 			fd(80);
 31: 			rt(120);
 32: 		}
 33: 		
 34: 		// 向きを上向きに戻す
 35: 		lt(30);
 36: 	}
 37: 	
 38: 	// 壁を描く
 39: 	void drawWall() {
 40: 		rt(90); // 向きを調節する
 41: 		//四角形を描く
 42: 		for (int i = 0; i < 4; i++) {
 43: 			fd(80);
 44: 			rt(90);
 45: 		}
 46: 		lt(90);// 向きを上向きに戻す
 47: 	}
 48: 	
 49: 	// 窓を描く
 50: 	void drawWindow() {
 51: 		// 窓を描く位置まで移動する
 52: 		// 前処理
 53: 		up();
 54: 		
 55: 		// 右へ
 56: 		rt(90);
 57: 		fd(22);
 58: 		
 59: 		// 下へ
 60: 		rt(90);
 61: 		fd(22);
 62: 		
 63: 		// 後処理
 64: 		rt(180);
 65: 		down();
 66: 		
 67: 		// 窓を描く
 68: 		rt(90);//向きを調節する
 69: 		for (int i = 0; i < 4; i++) {
 70: 			for (int j = 0; j < 4; j++) {
 71: 				fd(16);
 72: 				rt(90);
 73: 			}
 74: 			fd(16 * 2 + 4);
 75: 			rt(90);
 76: 		}
 77: 		lt(90);//向きを上向きに戻す
 78: 	}	
 79: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

12.4.3 窓付きの家を描くプログラム(2レベルをメソッド化)

次のプログラムでは、「屋根を描く」処理は「三角形を描く」という処理で、「壁を描く」処理は「四角形を描く」処理で、 「窓を描く」処理は「窓を描く位置に移動する」という処理と「小さな四角形を描く」処理で成り立っていると考え、 このレベルの処理をメソッド化しました。

リスト 12.4.3.1 House03.java
  1: /*
  2:  * 窓付きの家を描くプログラム(2レベルをメソッド化)
  3:  * 作成者:MegumiAraki
  4:  * 作成日:2007/06/09
  5:  * メールアドレス:garnet@sfc.keio.ac.jp
  6:  */
  7: 
  8: public class House03 extends Turtle {
  9: 
 10: 	//起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new House03());
 13: 	}
 14: 
 15: 	// 家を描く
 16: 	//タートルを動かす処理
 17: 	public void start() {
 18: 		drawRoof(); // 屋根を描く
 19: 		drawWall(); // 壁を描く
 20: 		drawWindow(); // 窓を描く
 21: 	}
 22: 
 23: 	// 屋根を描く
 24: 	void drawRoof() {
 25: 		drawTriangle(); // 三角形を描く
 26: 	}
 27: 
 28: 	// 壁を描く
 29: 	void drawWall() {
 30: 		rt(90); // 向きを調節する
 31: 		drawRectangle();// 四角形を描く
 32: 		lt(90);// 向きを上向きに戻す
 33: 	}
 34: 
 35: 	// 窓を描く
 36: 	void drawWindow() {
 37: 		// 窓を描く位置まで移動する
 38: 		moveToWindowLocation();
 39: 
 40: 		// 窓を描く
 41: 		rt(90);
 42: 		for (int i = 0; i < 4; i++) {
 43: 			drawSmallRectangle();
 44: 			fd(16 * 2 + 4);
 45: 			rt(90);
 46: 		}
 47: 		lt(90);
 48: 	}
 49: 
 50: 	// 三角形を描く
 51: 	void drawTriangle() {
 52: 		// 向きを調節する
 53: 		rt(30);
 54: 
 55: 		// 三角形を描く
 56: 		for (int i = 0; i < 3; i++) {
 57: 			fd(80);
 58: 			rt(120);
 59: 		}
 60: 
 61: 		// 向きを上向きに戻す
 62: 		lt(30);
 63: 	}
 64: 
 65: 	// 四角形を描く
 66: 	void drawRectangle() {
 67: 		for (int i = 0; i < 4; i++) {
 68: 			fd(80);
 69: 			rt(90);
 70: 		}
 71: 	}
 72: 
 73: 	// 小さい四角形を描く
 74: 	void drawSmallRectangle() {
 75: 		for (int i = 0; i < 4; i++) {
 76: 			fd(16);
 77: 			rt(90);
 78: 		}
 79: 	}
 80: 
 81: 	// 窓を描く位置まで移動する
 82: 	void moveToWindowLocation() {
 83: 		// 前処理
 84: 		up();
 85: 
 86: 		// 右へ22
 87: 		rt(90);
 88: 		fd(22);
 89: 
 90: 		// 下へ22
 91: 		rt(90);
 92: 		fd(22);
 93: 
 94: 		// 後処理
 95: 		rt(180);
 96: 		down();
 97: 	}
 98: 
 99: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

12.5 引数を用いたメソッドの抽象化

12.5.1 窓付きの家を描くプログラム(引数なしメソッド)

次のプログラムでは、メソッドを使い、「家を描く」処理を「屋根を描く」処理と、 「壁を描く」処理と、「窓を描く」処理に分けています。

「屋根を描く」処理では、「三角形を描く」処理を使い、「壁を描く」処理では、「四角形を描く」処理を、 「窓を描く」処理では「小さな四角形を描く」処理を使っています。

リスト 12.5.1.1 House03.java
  1: /*
  2:  * 窓付きの家を描くプログラム(2レベルをメソッド化)
  3:  * 作成者:MegumiAraki
  4:  * 作成日:2007/06/09
  5:  * メールアドレス:garnet@sfc.keio.ac.jp
  6:  */
  7: 
  8: public class House03 extends Turtle {
  9: 
 10: 	//起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new House03());
 13: 	}
 14: 
 15: 	// 家を描く
 16: 	//タートルを動かす処理
 17: 	public void start() {
 18: 		drawRoof(); // 屋根を描く
 19: 		drawWall(); // 壁を描く
 20: 		drawWindow(); // 窓を描く
 21: 	}
 22: 
 23: 	// 屋根を描く
 24: 	void drawRoof() {
 25: 		drawTriangle(); // 三角形を描く
 26: 	}
 27: 
 28: 	// 壁を描く
 29: 	void drawWall() {
 30: 		rt(90); // 向きを調節する
 31: 		drawRectangle();// 四角形を描く
 32: 		lt(90);// 向きを上向きに戻す
 33: 	}
 34: 
 35: 	// 窓を描く
 36: 	void drawWindow() {
 37: 		// 窓を描く位置まで移動する
 38: 		moveToWindowLocation();
 39: 
 40: 		// 窓を描く
 41: 		rt(90);
 42: 		for (int i = 0; i < 4; i++) {
 43: 			drawSmallRectangle();
 44: 			fd(16 * 2 + 4);
 45: 			rt(90);
 46: 		}
 47: 		lt(90);
 48: 	}
 49: 
 50: 	// 三角形を描く
 51: 	void drawTriangle() {
 52: 		// 向きを調節する
 53: 		rt(30);
 54: 
 55: 		// 三角形を描く
 56: 		for (int i = 0; i < 3; i++) {
 57: 			fd(80);
 58: 			rt(120);
 59: 		}
 60: 
 61: 		// 向きを上向きに戻す
 62: 		lt(30);
 63: 	}
 64: 
 65: 	// 四角形を描く
 66: 	void drawRectangle() {
 67: 		for (int i = 0; i < 4; i++) {
 68: 			fd(80);
 69: 			rt(90);
 70: 		}
 71: 	}
 72: 
 73: 	// 小さい四角形を描く
 74: 	void drawSmallRectangle() {
 75: 		for (int i = 0; i < 4; i++) {
 76: 			fd(16);
 77: 			rt(90);
 78: 		}
 79: 	}
 80: 
 81: 	// 窓を描く位置まで移動する
 82: 	void moveToWindowLocation() {
 83: 		// 前処理
 84: 		up();
 85: 
 86: 		// 右へ22
 87: 		rt(90);
 88: 		fd(22);
 89: 
 90: 		// 下へ22
 91: 		rt(90);
 92: 		fd(22);
 93: 
 94: 		// 後処理
 95: 		rt(180);
 96: 		down();
 97: 	}
 98: 
 99: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

12.5.2 窓付きの家を描くプログラム(引数を用いた、四角形を描くメソッドの抽象化)

次のプログラムでは、引数ありメソッドを使い、「壁を描く」処理で使っていた大きい四角形と 「窓を描く」処理の中で使っていた小さな四角形を「四角形を描く」というひとつのメソッドで描けるようにしています。

リスト 12.5.2.1 House04.java
  1: /*
  2:  * 窓付きの家を描くプログラム(引数を用いた四角形を描くメソッドの抽象化)
  3:  * 作成者:MegumiAraki
  4:  * 作成日:2007/06/09
  5:  * メールアドレス:garnet@sfc.keio.ac.jp
  6:  */
  7: public class House04 extends Turtle {
  8: 
  9: 	//起動処理
 10: 	public static void main(String[] args) {
 11: 		Turtle.startTurtle(new House04());
 12: 	}
 13: 
 14: 	// 家を描く
 15: 	//タートルを動かす処理
 16: 	public void start() {
 17: 		drawRoof(); // 屋根を描く
 18: 		drawWall(); // 壁を描く
 19: 		drawWindow(); // 窓を描く
 20: 	}
 21: 
 22: 	// 屋根を描く
 23: 	void drawRoof() {
 24: 		drawTriangle(80); // 三角形を描く
 25: 	}
 26: 
 27: 	// 壁を描く
 28: 	void drawWall() {
 29: 		rt(90); // 向きを調節する
 30: 		drawRectangle(80);// 四角形を描く
 31: 		lt(90);// 向きを上向きに戻す
 32: 	}
 33: 
 34: 	// 窓を描く
 35: 	void drawWindow() {
 36: 		// 窓を描く位置まで移動する
 37: 		moveToWindowLocation(22);
 38: 
 39: 		// 窓を描く
 40: 		rt(90);
 41: 		for (int i = 0; i < 4; i++) {
 42: 			drawRectangle(16);
 43: 			fd(16 * 2 + 4);
 44: 			rt(90);
 45: 		}
 46: 		lt(90);
 47: 	}
 48: 
 49: 	// 三角形を描く
 50: 	void drawTriangle(int size) {
 51: 		// 向きを調節する
 52: 		rt(30);
 53: 
 54: 		// 三角形を描く
 55: 		for (int i = 0; i < 3; i++) {
 56: 			fd(size);
 57: 			rt(120);
 58: 		}
 59: 
 60: 		// 向きを上向きに戻す
 61: 		lt(30);
 62: 	}
 63: 
 64: 	// 四角形を描く
 65: 	void drawRectangle(int size) {
 66: 		for (int i = 0; i < 4; i++) {
 67: 			fd(size);
 68: 			rt(90);
 69: 		}
 70: 	}
 71: 
 72: 	// 窓を描く位置まで移動する
 73: 	void moveToWindowLocation(int length) {
 74: 		// 前処理
 75: 		up();
 76: 
 77: 		// 右へ
 78: 		rt(90);
 79: 		fd(length);
 80: 
 81: 		// 下へ
 82: 		rt(90);
 83: 		fd(length);
 84: 
 85: 		// 後処理
 86: 		rt(180);
 87: 		down();
 88: 	}
 89: 
 90: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

12.5.3 窓付きの家を描くプログラム(引数を用いた、多角形を描くメソッドの抽象化)

次のプログラムでは「屋根を描く」処理で使っていた三角形と、「壁を描く」「窓を描く」処理で使っていた四角形を 「多角形を描く」というひとつのメソッドで描けるようにしています。

リスト 12.5.3.1 House05.java
  1: /*
  2:  * 窓付きの家を描くプログラム(引数による多角形を描くメソッドの抽象化)
  3:  * 作成者:MegumiAraki
  4:  * 作成日:2007/06/09
  5:  * メールアドレス:garnet@sfc.keio.ac.jp
  6:  */
  7: 
  8: public class House05 extends Turtle {
  9: 
 10: 	//起動処理
 11: 	public static void main(String[] args) {
 12: 		Turtle.startTurtle(new House05());
 13: 	}
 14: 
 15: 	// 家を描く
 16: 	 //タートルを動かす処理
 17: 	public void start() {
 18: 		drawRoof(); // 屋根を描く
 19: 		drawWall(); // 壁を描く
 20: 		drawWindow(); // 窓を描く
 21: 	}
 22: 
 23: 	// 屋根を描く
 24: 	void drawRoof() {
 25: 		drawRegularPolygon(3, 80); // 三角形を描く
 26: 	}
 27: 
 28: 	// 壁を描く
 29: 	void drawWall() {
 30: 		rt(90); // 向きを調節する
 31: 		drawRegularPolygon(4, 80);// 四角形を描く
 32: 		lt(90);// 向きを上向きに戻す
 33: 	}
 34: 
 35: 	// 窓を描く
 36: 	void drawWindow() {
 37: 		// 窓を描く位置まで移動する
 38: 		moveToWindowLocation(22);
 39: 
 40: 		// 窓を描く
 41: 		rt(90);
 42: 		for (int i = 0; i < 4; i++) {
 43: 			drawRegularPolygon(4, 16);
 44: 			fd(16 * 2 + 4);
 45: 			rt(90);
 46: 		}
 47: 		lt(90);
 48: 	}
 49: 
 50: 	// 指定された角数の正多角形を描く
 51: 	void drawRegularPolygon(int n, int size) {
 52: 		// 向きを調節する
 53: 		double angle = 360d / (double) n;
 54: 		rt(angle - 90);
 55: 
 56: 		// 多角形を描く
 57: 		for (int i = 0; i < n; i++) {
 58: 			fd(size);
 59: 			rt(angle);
 60: 		}
 61: 
 62: 		// 向きを上向きに戻す
 63: 		lt(angle - 90);
 64: 	}
 65: 
 66: 	// 窓を描く位置まで移動する
 67: 	void moveToWindowLocation(int length) {
 68: 		moveTurtle(90, 22);// 右へ
 69: 		moveTurtle(180, 22);// 下へ
 70: 	}
 71: 
 72: 	// 指定された方向に(ペンを上げて)移動する
 73: 	void moveTurtle(double direction, int distance) {
 74: 		up();
 75: 		rt(direction);
 76: 		fd(distance);
 77: 		lt(direction);
 78: 		down();
 79: 	}
 80: 
 81: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

12.6 課題

12.6.1 問題1-1:中心角を指定して円弧を描くメソッドを作ろう

drawArc(int angle)のように、中心角を指定して円弧を描くメソッドを作ろう。

(ヒント:中心角が360ならば円に、180ならば半円に、1ならば点のようになります。以下に、120度の場合と、300度の場合の例を示します)

図 12.6.1.1 円弧を描くメソッド
図 12.6.1.2 円弧を描くメソッド2

12.6.2 問題1-2:円弧を描くメソッドを使って猫の目を描こう

円弧を描くメソッドを使って、drawCatEyes()のように猫の目を描くメソッドを作ろう。(start()メソッドの中に、drawCatEyes();とだけ書けば猫の目が描けるようにする)

(ヒント:猫の目を描くには、レモン型を描くメソッドdrawLemon()を作って、それを2つ並べるとよい。)

図 12.6.2.1 レモン型を描くメソッド
図 12.6.2.2 猫の目を描くメソッド

12.6.3 問題1-3:円弧を描くメソッドを使って蝶を描こう

円弧を描くメソッドを使って、drawButterfly()のように蝶を描くメソッドを作ろう。(start()メソッドの中に、drawButterfly();とだけ書けば蝶が描けるようにする)

(ヒント:円弧を描くメソッドのほかにも、レモン型を描くメソッドなどを部品として使うと楽に描ける)

図 12.6.3.1 蝶を描くメソッド

12.6.4 問題1-4:円弧を描くメソッドを使って花を描こう

円弧を描くメソッドを使って、drawFlower()のように花を描くメソッドを作ろう。(start()メソッドの中に、drawFlower();とだけ書けば花が描けるようにする)

(ヒント:レモン型を描くメソッドなどを部品として使うと楽に描ける)

図 12.6.4.1 花を描くメソッド

12.6.5 問題2:入力によって猫の目、蝶、花を描き分けるプログラムを作ろう

1を入力したら猫の目を、2を入力したら蝶を、3を入力したら花を描くプログラムを作ろう。

12.7 おまけ問題

メソッドが自分自身を呼び出す処理を、再帰メソッド呼び出しと言う。

これは、発展的で面白いプログラミングテクニックである。

12.7.1 再帰を使って木を描くサンプルプログラム

リスト 12.7.1.1 DrawTree.java
  1: /*
  2:  * 発展例題1:再帰を使って木を描くプログラム
  3:  * (メソッドの再帰呼び出し)
  4:  * 作成者:MegumiAraki
  5:  * 作成日:2007/06/09
  6:  * メールアドレス:garnet@sfc.keio.ac.jp
  7:  */
  8: 
  9: public class DrawTree extends Turtle {
 10: 
 11: 	// 起動処理
 12: 	public static void main(String[] args) {
 13: 		Turtle.startTurtle(new DrawTree());
 14: 	}
 15: 
 16: 	// タートルを動かす処理
 17: 	public void start() {
 18: 
 19: 		bk(100);// 木を描く位置まで移動する
 20: 		drawTree(1, 100);// 枝分かれの数を1とし、幹の長さを100として、木を描く。
 21: 
 22: 	}
 23: 
 24: 	// 木を描く
 25: 	void drawTree(int branchNumber, int length) {
 26: 		// メソッド開始のデバッグ出力をする
 27: 		debugStart(branchNumber, length);
 28: 
 29: 		if (branchNumber == 6) {
 30: 
 31: 			fd(length);
 32: 			bk(length);
 33: 
 34: 		} else {
 35: 
 36: 			fd(length);
 37: 
 38: 			// 右の枝を描く
 39: 			rt(30);
 40: 			drawTree(branchNumber + 1, length / 2);
 41: 			lt(30);
 42: 
 43: 			// 左の枝を描く
 44: 			lt(30);
 45: 			drawTree(branchNumber + 1, length / 2);
 46: 			rt(30);
 47: 
 48: 			bk(length);
 49: 
 50: 		}
 51: 
 52: 		// メソッド終了のデバッグ出力をする
 53: 		debugEnd(branchNumber);
 54: 	}
 55: 
 56: 	// メソッド開始のデバッグ出力をする
 57: 	void debugStart(int outputBranchNum, int outputLength) {
 58: 		for (int i = 0; i < outputBranchNum; i++) {
 59: 			System.out.print("\t");// タブで空白を空ける
 60: 		}
 61: 
 62: 		print("木を描く(枝分かれの数:" + outputBranchNum + "、幹の長さ:" + outputLength + ")。");
 63: 
 64: 	}
 65: 
 66: 	// メソッド開始のデバッグ出力をする
 67: 	void debugEnd(int drawnBranchNum) {
 68: 		for (int i = 0; i < drawnBranchNum; i++) {
 69: 			System.out.print("\t");// タブで空白を空ける
 70: 		}
 71: 
 72: 		print("//");
 73: 
 74: 	}
 75: 
 76: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

12.7.2 おまけ問題1:再帰を使って自然な木を描くプログラム

木を描くサンプルプログラムを乱数を使うように改造して、自然な木を描くプログラムにしよう。

枝の生える角度と、長さを乱数にします。

【自然な木に見せるためのヒント】

図 12.7.2.1 自然な木

12.7.3 おまけ問題2:再帰を使ってコッホ曲線を描くプログラム

図 12.7.3.1 コッホ曲線

ノーヒント