Powered by SmartDoc

2 問題領域の段階的プログラミング

段階的にプログラミングすることとオブジェクトの性質を抽出することは同じではないが、OOPにおいてはオブジェクトの所有する本質的な部分を最初に実装し、その後に修飾部分を実装するのが一般的なプログラミングスタイルである。

Javaを使って、このカウンタ問題を解きながら、現在のJavaの環境と開発スタイルについて整理してみる。

2.1 カウンタの機能と属性

これから作成する「カウンタ」をポンチ絵で表したのが、下図である。(1)

(2)図から明らかなようにカウンタへの操作としては、

がある。また、モデルが保持しなければならない情報としては、

が必要であることが分かる。

このようなカウンタが持つべき概念的な属性や機能はアブストラクト・クラスとして定義し、アブストラクト・クラスの機能を実装した節[整数カウンタクラス(IntegerCount)]をサブクラスとする。AbstractCountクラスはアブトラクト・クラスであるためインスタンスを生成するメソッドを持っていない、increment, decrement, toStringは下位クラスで実装が必要なアブストラクトメソッドであるため、右側に○にAのアイコンが表示されている。IngegerCountがAbstractCountのコンクリートクラス(コンストラクタを持つクラス)であり、ここでincrement, decrementメソッドを定義している。

整数カウンタのUMLのクラス構成を図[整数カウンタクラス構成]に示す。(4)

図 2.1.1 整数カウンタクラス構成
  1. この例は、"Object-Oriented Programming"のカウンタ問題から引用したものである。"Object-Oriented Programming"では、この問題をSmalltalkとC++で実装し、それぞれを比較していたが、ここではjavaを使って実装し、他の言語との違いにも言及する。
  2. Object-Oriented Programming Fig 1-12から引用。
  3. 値を文字列として取得するメソッドは、GUI構築で必要なのでtoStringを追加した
  4. このUML図は、EclipseのUML Pluginを使って作成した。

2.2 カウンタのインタフェース

最初にカウンタモデルと外界とのインタフェースについて、記述する。(5)カウンタのインタフェースは、前節のincrement, decrement, resetの3個である。これをjavaで記述すると以下のようになる。

リスト 2.2.1 ICounter.java
package model;

/**
 * カウンタのインタフェース
 * 
 * @author Hiroshi TAKEMOTO
 * @version $Id$
 */
public interface ICount {
	/**
	 * カウンタを加算する(1カウントアップ)
	 */
	public void increment();
	/**
	 * カウンタを減算する(1カウントダウン)
	 */
	public void decrement();
	/**
	 * カウンタをリセットする
	 */
	public void reset();
}
  1. "Object-Oriented Programming"では、アブストラクトクラスにインタフェースを記述していたが、javaのinterface文を使った方がクラス階層に依存しないので、使用できるモデルの幅が広がる。これがjavaを使ったモデルの特徴である。

2.3 アブストラクトカウントクラス

インタフェースの次にカウントクラスの概念クラスを作成する。概念クラスには、カウンタが持つべき共通の機能や属性を定義する。概念クラスの特徴としては、コンストラクタを持たないこと、実装がない概念メソッドが存在することがあげられる。カウンタのアブストラクトカウントクラスをリスト[AbstractCount.java]に示す。

リスト 2.3.1 AbstractCount.java
package model;

/**
 * カウントのアブストラクトクラス
 * 
 * @author Hiroshi TAKEMOTO
 * @version $Id$
 */
public abstract class AbstaractCount implements ICount {
	/**
	 * 現在の値
	 */
	private Object	value_ = null;
	/**
	 * リセット値
	 */
	private Object	resetValue_ = null;
	
	/**
	 * @see model.ICount#increment()
	 */
	public abstract void increment();

	/**
	 * @see model.ICount#decrement()
	 */
	public abstract void decrement();
	
	/**
	 * @see java.lang.Object#toString()
	 */
	public abstract String toString();
	
	/**
	 * @see model.ICount#reset()
	 */
	public void reset() {
		setValue_(getResetValue_());
	}
	/**
	 * Returns the resetValue_.
	 * @return Object
	 */
	protected Object getResetValue_() {
		return resetValue_;
	}

	/**
	 * Returns the value_.
	 * @return Object
	 */
	public Object getValue_() {
		return value_;
	}

	/**
	 * Sets the resetValue_.
	 * @param resetValue_ The resetValue_ to set
	 */
	protected void setResetValue_(Object resetValue_) {
		this.resetValue_ = resetValue_;
	}

	/**
	 * Sets the value_.
	 * @param value_ The value_ to set
	 */
	public void setValue_(Object value_) {
		this.value_ = value_;
	}
}

(6)

  1. 「MVCの検証」では、resetValueは、クラスで1個決まった値を持つものなので、staticでクラス変数として宣言したが、インスタンス毎にリセット値を持つことができようにインスタンス変数に変更した。

2.4 整数カウンタクラス(IntegerCount)

次に、整数カウンタクラスを作成する。オブジェクトを値とするために、整数値を内部データ型(int)ではなく、Integerクラスを使ってラップしたために、加算と減算の手続きに少し無理がある。

value_ = new Integer(((Integer)value_).intValue() + 1);
		

のようにvluae_を(Integer)にキャストして、intValue()でその整数値を取得し、1足した後、その値を整数値として持つIntergerオブジェクトを生成してvalue_にセットしている。また、リセット値は0と使用した。

リスト 2.4.1 IntegerCount.java
package model;

/**
 * 整数カウンタ
 * 
 * @author Hiroshi TAKEMOTO
 * @version $Id: IntegerCount.java,v 1.1.1.1 2003/11/14 20:23:36 take Exp $
 */
public class IntegerCount extends AbstaractCount {	
	/**
	 * 整数カウンタのコンストラクタ
	 */
	public IntegerCount() {
		setResetValue_(new Integer(0));
		reset();
	}
	
	/**
	 * @see model.ICount#increment()
	 */
	public void increment() {
		setValue_(new Integer(((Integer)getValue_()).intValue() + 1));
	}

	/**
	 * @see model.ICount#decrement()
	 */
	public void decrement() {
		setValue_(new Integer(((Integer)getValue_()).intValue() - 1));
	}
	
	/**
	 * @see java.lang.Object#toString()
	 */
	public String toString(){
		return (((Integer)getValue_()).toString());
	}	
}

2.5 Eclipseを使ってプログラミング

実際にEclipseを使って整数カウンタを作成してみる。Eclipseのインストール等環境開発の手順については、下記を参照されたい。また、整数カウンタの作成手順をMicrosoft Mutlimedia Playerのムービーとして作成したので、movies/mov_2.5_1.wmvからダウンロードして参照されたい。

2.5.1 プロジェクトの作成

Eclipseのアイコンをダブルクリックして、Eclipseを起動する。Eclipseでは、「プロジェクト」という単位でプログラムを管理しているため、まず最初にプロジェクトを作成する必要がある。以下の手順でプロジェクトを作成する。

  1. メニューから「ファイル」→「新規」→「プロジェクト」を選択し、「新規プロジェクト」ダイアログを表示する
  2. 「Java」から「Javaプロジェクト」を選択し、「次へ」ボタンを選択する
  3. 「Javaプロジェクト」画面で「プロジェクト名」を入力する。ここでは“MVC”と入力した
  4. 「Java設定」画面で、「プロジェクトに含まれるソース・フォルダを使用」を選択し、「新規フォルダーの作成ボタンを押し、「新規ソース・フォルダ」名に“src”と入力し、「ビルド出力フォルダーMVC/binに変更しますか?」の問い合わせで「はい」を選択し、「終了」ボタンを押す
  5. カウンタモデルをパッケージ“model”として作成するために、新規で“model”パッケージを作成する。「src」アイコンを選択して、右クリックから「新規」→「パッケージ」を選択し、「名前」に“model”と入力する
図 2.5.1.1 Javaプロジェクト画面

2.5.2 ICountインタフェースの作成(ICount)

最初にICountインタフェースを作成する。(7)

  1. 「model」パッケージを選択し、右クリックで、「新規」→「インタフェース」を選択する
  2. 「Javaインタフェース」ダイアログの「名前」に“ICount”と入力し、「終了」ボタンを選択する
  3. テンプレートが展開され、コメントがセットされたICount.javaファイルが生成される(8)
  4. リスト[ICounter.java]を参考に以下のメソッド定義を入力する
    	public void increment();
    	public void decrement();
    	public void reset();						
    					
    
  5. Eclipseの「javaコメントの追加」機能を使ってjava doc用のコメントを挿入する「increment()」メソッドの行を選択し、右クリックから「ソース」→「Javadocコメントの追加」を選択するとメソッドのコメントテンプレートが生成されるので、これを修正し、リスト[ICounter.java]の様にカット・ペーストでコメントを挿入する。(9)
図 2.5.2.1 テンプレートから生成されたICount.java
  1. どの順番で作成しても問題はないが、インタフェースを先に作成する事によって、AbstractCountを作成する時に、Eclipseが自動的に必要なメソッドのテンプレートを作成する機能を活用するために最初にICountを作成する。
  2. 例では、「ウィンドウ」→「設定」→「java」→「テンプレート」から、「typecomment」を私のよく使う設定に変更したものが表示されているので、適宜自分の設定に修正されたい。
  3. 引数がある場合には、引数名と型が自動的に挿入される

2.5.3 AbstractCountクラスの作成(AbstractCount)

次にカウンタの概念クラスであるAbstractCountを作成する。

  1. 「model」パッケージを選択し、右クリックで、「新規」→「クラス」を選択する
  2. Javaクラスダイアログの名前に“AbstractCount”と入力し、「abstract」のチェックボックスをチェックする
  3. 「追加」ボタンで実装するインタフェースからICountを選択する
  4. 「継承された抽象メソッド」チェックボックスをチェックする
  5. increment, decrementをabstractメソッドと定義する
    	public abstract void increment();
    	public abstract void decrement();
    					
    
  6. resetメソッドを下記のように定義する
    	public void reset() {
    		setValue_(getResetValue_());
    	}						
    					
    
  7. プライベート変数、value_, resetValue_を宣言する
    	private Object	value_ = null;
    	private Object	resetValue_ = null;
    					
    
  8. 右クリックから「ソース」→「Getterおよびsetterの生成」を選択し、「すべてを選択」を選択し、「OK」ボタンを押す。resetValue_は、下位クラス以外にはアクセスされたくない性質の変数なので、publicからprotectedに変更する。

2.5.4 IntegerCountクラスの作成

最後に、整数カウンタのIntegerCountクラスを作成する。

  1. 「model」パッケージを選択し、右クリックで、「新規」→「クラス」を選択する
  2. Javaクラスダイアログの名前に“IntegerCount”と入力し、「スーパークラス」に「ブラウズ」ボタンを選択して、「AbstractCount」を選択し、「OK」ボタンを押す。
  3. AbstractCountで未定義だったincrement, decrementだけが、テンプレートメソッドとして生成される
  4. 引数のないコンストラクタAbstractCount()を以下のように定義する

    	public IntegerCount() {
    		setResetValue_(new Integer(0));
    		reset();
    	}
    					
    

    ムービーの例の様に、“this”をsetResetValue_の前に置いて、this.とタイプすると入力候補が表示される。この入力補完機能は、CTRL-スペースを押すことによっても表示することができる。

  5. 値を表示するメソッドtoString()を定義する
    	public String toString(){
    		return (((Integer)getValue_()).toString());
    	}	
    					
    

これで、整数カウンタが完成した。

2.6 メイン関数を作らないで動作確認

Eclipseには、「スクラックブック」という機能があり、メイン関数を作らなくてもjavaの断片を評価し実行する機能がある。これを使ってIntegerCountの動作を確認する。

2.6.1 スクラックブックを使った動作確認

以下の手順でスクラップブックを作成し、IntegerCountの動作を確認する。

  1. MVCを選択して、右クリックから「新規」→「スクラップブック・ページ」を選択する
  2. 「ファイル名」にPDCTestと入力して「終了」ボタンを選択する
  3. スクラップブックに以下のjavaコード断片を入力する(//以下のコメントは不要)
    ICount c = new IntegerCount();			// IntegerCountのインスタンスcを生成する
    c.increment();							// cのカウントを1増やす
    System.out.println(c);					// cの現在の値を表示する
    c.increment();							// cのカウントを1増やす
    System.out.println(c);					// cの現在の値を表示する					
    c.increment();							// cのカウントを1増やす
    System.out.println(c);					// cの現在の値を表示する
    c.decrement();							// cのカウントを1減らす
    System.out.println(c);					// cの現在の値を表示する										
    c.reset();								// cをリセットする
    System.out.println(c);					// cの現在の値を表示する
    					
    
  4. このままでは、パッケージmodelのIntegerCountの型が解決できないため、modelパッケージをインポートする必要がある。スクラップブックで、右クリックから「インポートの設定」を選択し、「パッケージの追加」ボタンを押して、一覧からmodelを選択する。
  5. スクラップブックの内容を全て選択し、右クリックから「断片の実行」を選択すると、コンソール画面に以下の結果が表示される。
    1
    2
    3
    2
    0
    					
    
図 2.6.1.1 スクラップブック・テスト

2.6.2 もう一つのテスト環境(Pnuts)

Pnutsは、javaのプログラムのテストを簡単に行うために開発されたインタプリタ形式の言語処理系である。(10)そのため、スクラップブックのようにjava言語ではなく、タイプ宣言のない、独自の言語仕様を使って記述するため、記述量も少なく、テストが短時間で行うことができる。スクラップブックは、評価を一括して行うのに対し、pnutsを使ったテストは、実行結果を保持しながら逐次的に処理を実行し、確認することができるのが大きな特徴である。pnutsのインストールについては、下記を参照されたい。Eclipseでpnutsを使用する場合の設定方法は、次の通りである。

Pnutsを使ったテストの作成手順をMicrosoft Mutlimedia Playerのムービーとして作成したので、movies/mov_2.6_1.wmvからダウンロードして参照されたい。

  1. 右クリックから「新規」→「フォルダー」を選択し、フォルダー名にlibを指定する
  2. libを選択し、右クリックから「インポート」を選択し、インポートソースから「ファイルシステム」を選択し、ブラウザからpnuts.jarとpnutool.jarを選択し、終了ボタンを押す
  3. インポートしたjarファイルをクラスパスに追加するために、MVCを選択し、右クリックからプロパティーを選択し、「ライブラリ」タグで「JARの追加」ボタンを選択し、lib以下のpnuts.jarとpnutool.jarを選択する
  4. メニューの「実行」(11)を選択し、「javaアプリケーション」を選択し、右クリックから「新規」を選択する
  5. 「名前」にPnutToolと入力し、「メインクラス」にpnuts.precompiled.pnutoolと入力し、実行ボタンを押す
  6. pnutoolウィンドウの上部パネルに以下のスクリプトを入力する
    import("model.*")			// モデルのインポート宣言
    
    count = IntegerCount()		// IntegerCountの生成
    count.increment()			// 1カウントアップ
    println(count)				// 現在の値を出力
    count.increment()
    count.increment()
    count.increment()
    println(count)
    					
    
  7. 編集メニューから「すべて選択」を選択し、「ファイル」→「計算」を選択するとスクリプトを実行する。pnutoolウィンドウの下部パネルに実行結果(評価結果)が表示される
図 2.6.2.1 pnutsを使ったテスト
  1. pnutsは、日本人の戸松氏が開発された国産のインタプリタ言語である
  2. または、ツールバーの実行アイコン

2.7 Junitを使った単体テスト

Eclipseは、Junitに対応しているため、Junitを使った単体テストをEclipseの環境内で実行することができる。特に、エラーが発見されたときに、その実行結果をクリックすると失敗したメソッドが表示されるので、デバッグが非常に楽になる。(12)JUnitのテストプログラムをパッケージに含めるか否かについては議論があるが、私はmodelと同じレベル“unittest”というパッケージにJunitのテストケースを入れることにしている。このようにすることで、プロジェクトの単体テストがスムーズに行え、出荷時に不要ならばunittestを削除するだけで済む。以下にEclipseを使ったJunitのテストケースの追加方法を示す。

  1. unittestパッケージディレクトリを作成する
  2. 例としてPDC_Modeltest.javaをTestCaseのサブクラスとして作成する
  3. 各テストケース(testで始まるpublic void型のメソッド)毎にIntegerCountのインスタンスを生成するように、setUpとtearDownメソッドを定義する
  4. 最初にどのようなテストを行うかを箇条書きにして、それをコメントアウトする
    	// incrementoのテスト
    	// decrementのテスト
    	// resetのテスト	
    	// reset後のincrementのテスト	
    	// reset後のdecrementのテスト	
    	// increment, decrement, resetの混合					
    				
    
  5. 各テストメソッドを記述し、予想結果と実際の処理結果をassertEqualsメソッドを使って比較するテストプログラムのリストをリスト[PDC_Modeltest.java]に示す。
    リスト 2.7.1 PDC_Modeltest.java
    package unittest;
    
    import model.IntegerCount;
    
    import junit.framework.TestCase;
    
    /**
     * 問題領域でのモデルの単体テスト
     * @author Hiroshi TAKEMOTO
     * 
     * @version $Id$
     */
    public class PDC_ModelTestCase extends TestCase {
    	private IntegerCount	count = null;
    	
        public void setUp()
        {
        	count = new IntegerCount();
        }
    
        public void tearDown()
        {
    	   	count = null;
        }
    	// 生成されたインスタンスの値をチェック
    	public void testConstractor() {
    		// 初期値が0であることを確認する
    		this.assertEquals(count.getValue_(), new Integer(0));
    	}
    	
    	// incrementoのテスト
    	public void testIncrement() {
    		// 生成、直後のincrement
    		count.increment();
    		this.assertEquals(count.getValue_(), new Integer(1));
    		// incrementを複数繰り返した後の値
    		count.increment();
    		count.increment();
    		count.increment();
    		this.assertEquals(count.getValue_(), new Integer(4));		
    	}
    	
    
    	// decrementのテスト
    	public void testDecrement() {
    		// 生成、直後のdecrement
    		count.decrement();
    		this.assertEquals(count.getValue_(), new Integer(-1));
    		// decrementを複数繰り返した後の値
    		count.decrement();
    		count.decrement();
    		count.decrement();
    		this.assertEquals(count.getValue_(), new Integer(-4));
    	}
    		
    	// resetのテスト
    	public void testReset() {
    		// 生成、直後のreset
    		count.reset();
    		this.assertEquals(count.getValue_(), new Integer(0));
    		// incrementを複数繰り返した後のreset
    		count.increment();
    		count.increment();
    		count.increment();
    		count.reset();		
    		this.assertEquals(count.getValue_(), new Integer(0));
    	}
    	
    	// reset後のincrementのテスト
    	public void testIncrementAfterReset() {
    		count.increment();
    		count.increment();
    		count.increment();
    		this.assertEquals(count.getValue_(), new Integer(3));
    		count.reset();		
    		this.assertEquals(count.getValue_(), new Integer(0));
    		count.increment();
    		this.assertEquals(count.getValue_(), new Integer(1));
    	}
    	
    	// reset後のdecrementのテスト
    	public void testDecrementAfterReset() {
    		count.decrement();
    		count.decrement();
    		count.decrement();
    		this.assertEquals(count.getValue_(), new Integer(-3));
    		count.reset();		
    		this.assertEquals(count.getValue_(), new Integer(0));
    		count.decrement();
    		this.assertEquals(count.getValue_(), new Integer(-1));
    	}
    	
    	// increment, decrement, resetの混合
    	public void testMixedOperation() {
    		count.increment();
    		count.increment();
    		count.decrement();
    		this.assertEquals(count.getValue_(), new Integer(1));
    		count.reset();
    		this.assertEquals(count.getValue_(), new Integer(0));
    		count.decrement();
    		count.decrement();
    		count.increment();
    		this.assertEquals(count.getValue_(), new Integer(-1));				
    	}
    	
    }
    
  6. 「実行」メニューから「実行」を選択し、起動構成から「Junit」を選択し、右クリックで「新規」を選択し、名前にPDC_ModelTestCaseを入力し、「テスト・クラス」にunittest.PDC_ModelTestCaseを入力して、「実行」ボタンを押すとJUnitが起動する。
図 2.7.1 JUnitの実行
  1. 私の使用しているEclipse 2.01では、junit用のjarファイルをあらかじめクラスパスに追加する必要があるため、pnutsのjarファイルをインポートしたのと同じ手順でlibにjunit.jarをインポートし、クラスパスに追加しておく。

2.8 IntegerCountの改造

これで、整数カウンタの作成とテストが完了したので、整数カウンタを拡張してみる。

2.8.1 コンストラクタの追加

リセット値が異なるカウンタを作成したいニーズがでてくる。このような場合に、便利なのがインスタンスを生成するコンストラクタを複数用意する事である。整数カウンタにリセット値指定のコンストラクタを以下のように定義する。

	/**
	 * 初期値(リセット値)指定の整数カウンタのコンストラクタ
	 */
	public IntegerCount(int initial) {
		setResetValue_(new Integer(initial));
		reset();
	}				
			

2.8.2 16進カウンタへの拡張

次に16進数で表示するカウンタを考えてみる。整数カウンタとの違いは、表示方法だけなのでtoStringメソッドのみを修正することになる。従ってIntegerCountのサブクラスとして、HexCountクラスを作成する。

リスト 2.8.2.1 HexCounter.java
package model;

/**
 * 16進カウンタ
 * 
 * @author Hiroshi TAKEMOTO
 * 
 * @version $Id$
 */
public class HexCount extends IntegerCount {	
	/**
	 * @see java.lang.Object#toString()
	 */
	public String toString() { 
		// 16進表示は、0xA0のように最初に0xをつけた
		return ("0x" + Integer.toString(((Integer)this.getValue_()).intValue(), 16).toUpperCase());
	}	
}

作成したHexCountを整数カウンタと同様にテストしてみる。スクラップブックのPDCTest.jpageをコンストラクタ部分を以下のように変更して、

ICount c = new HexCount();		// HexCountのインスタンスcを生成する				
			

実行すると次のように出力される。

0x1
0x2
0x3
0x2
0x0				
			

2.8.3 カレンダカウンタの作成

カウンタの最後の例題としてカレンダカウンタを実装する。まず、仕様を決める。

java APIからそれらしいクラスを検索してみる。それらしいDateクラスが見つかったので、スクラップブックで動作を調べてみる。

Date d = new Date();
System.out.println(d)				
			

と入力し、インポートにjava.util.dateを追加し、評価すると

Wed Dec 03 17:04:46 JST 2003				
			

と表示される。しかし、Dateクラスでは、日付のカウントができない。Calendarクラスには、addメソッドが用意されおり、日付の増減が可能であり、今回の目的に合致する。Calendarから日付を取り出すには、getTimeメソッドを使うことにする。試しにbshで動作を確認してみる。Java APIの説明からカット&ペーストするだけでAPIの動作を確認することができるのもスクラップブックの利点である。

Calendar now = Calendar.getInstance();  // Calendarのインスタンス生成を変数nowにセット
System.out.println(now.getTime());
now.add(Calendar.DATE, 1);    			// add()で日付を1日増やす
System.out.println(now.getTime());	
			

を評価すると、

Wed Dec 03 17:11:34 JST 2003
Thu Dec 04 17:11:34 JST 2003				
			

が得られる。よって求めるカレンダカウンタは、次のようになる。

リスト 2.8.3.1 CalendarCounter.java
package model;

import java.util.Calendar;
import java.util.Date;

/**
 * カレンダカウンタ
 * 
 * @author Hiroshi TAKEMOTO
 * 
 * @version $Id$
 */
public class CalendarCount extends AbstaractCount {
	private Calendar now_;
	
	public CalendarCount() {
		now_ = Calendar.getInstance();		// Calendarのインスタンスを生成する	
		setResetValue_(now_.getTime());		// 現在時刻をリセット値にセットする
		reset();
	}
	
	/**
	 * @see model.ICount#increment()
	 */
	public void increment() {
		now_.add(Calendar.DATE, 1);    		// 日付を1増やす
		setValue_(now_.getTime());
	}

	/**
	 * @see model.ICount#decrement()
	 */
	public void decrement() {
		now_.add(Calendar.DATE, -1);    	// 日付を1減らす
		setValue_(now_.getTime());
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		return (((Date)getValue_()).toString());
	}
}

HexCountと同様にスクラップブックで、

ICount c = new CalendarCount();		// CalendarCountのインスタンスcを生成する				
			

テストすると、

Thu Dec 04 17:49:05 JST 2003
Fri Dec 05 17:49:05 JST 2003
Sat Dec 06 17:49:05 JST 2003
Fri Dec 05 17:49:05 JST 2003
Wed Dec 03 17:49:05 JST 2003				
			

2.9 GUIとの結合の前に

問題領域でのカウントの例題にGUIを追加する前に、pnutsを使ってGUIを追加する方法を紹介する。値とボタンを含むフレームを作ってみる。

図 2.9.1 pnutsを使ったGUI作成

このフレームを表示するpnutsスクリプトは、次のようになる。

リスト 2.9.1 pnut_gui.pnuts
import("javax.swing.*")
import("model.*")

m = IntegerCount()
f = JFrame("GUI Model Test")
p = JPanel()
l = JTextField(5)
b = JButton("increment")
p.add(l)
p.add(b)
f.getContentPane().add(p)
f.pack()
f.show()

function callback(e) {
	m.increment()
	l.setText(m.getValue_().toString())
}

bind(b, "actionPerformed", callback)

スクリプトの実行は、「実行」メニューからPnutsToolを選択し、Pnutsの「ファイル」メニューから「読み込む」を選択しpnut_gui.pnutsを読みと図[pnutsを使ったGUI作成]が表示する。Pnutsウィンドウの上部パネルに

m.increment()
m.increment()
l.setText(m.getValue_().toString())
m.reset()
println(m)			
		

と入力すると、

図 2.9.2 pnut_gui.pnutsの実行状況

の様に、GUIを表示しながら、pnutsのスクリプトパネル(上部パネル)で" m.reset() "のように動的にコマンドを実行しながら、オブジェクトを変更することができる。これがインタプリタの大きな特徴である。

以上のように、javaのインタプリタを使うことによってテストに要する時間が短縮され、テスト方法の自由度も増すことが検証できた。

2.10 まとめ

問題領域の段階的プログラミングとして、ここでは

ことを検証できた。問題領域で作成したクラスの構成をUMLで記述する。

図 2.10.1 問題領域で作成したクラス構成

作成したプログラムの構造や技術的なポイントを後ですぐに取り戻すことができるように整理することが大切である。(13)

    • プログラムの構造をUMLで表現してみる
    • プログラムの技術ポイントをドキュメントに残す
    • プログラムにコメントを付加し、javadocでHTMLに変換しておく
    • プログラムやドキュメントはCVS等のバージョン管理ソフトを使って変更履歴をとり、いつでも以前の任意の時点に戻せるようにする