チャットbotお試し用アプリ開発_6日目

# 目次

・本日の成果・考え
・最後に

### 本日の成果
本日よりPG開始しました。
PGとUTを同時実施する関係で、全ての処理のDTOに使用する設定ファイルDTOから開始しました。

``` AppSettingDto.java
package app.config;

/**
 * 設定ファイルのDtoクラス。
 * @author 
 * @version 1.0
 */
class AppSettingDto {
	
	/*
	 属性:タイトル、表示URL、ウィンドウ幅、ウィンドウ高さ
	*/
	private final String logPass;
	private final String logFileExtensionString;
	private final String title;
	private final String windUrl;
	private final int windWidth;
	private final int windHeight;
	public static AppSettingDto appSettingDto;
	

	//************
	// メソッド名：引数付きコンストラクタ
	// 処理内容：インスタンス生成用コンストラクタ
	/************/
	
	private AppSettingDto(String logPass,
			              String logFileExtension,
			              String title,
			              String windUrl,
			              int windWidth,
			              int windHeight){
		this.logPass= logPass;
		this.logFileExtensionString = logFileExtension;
		this.title = title;
		this.windUrl = windUrl;
		this.windWidth = windWidth;
		this.windHeight = windHeight;
	}
	
	//************
	// メソッド名：インスタンス生成メソッド
	// 処理内容：重複チェックをした後に、引数つきコンストラクタを呼び出す。
	/************/
	public static void createInstance(String logPass,
            String logFileExtension,
            String title,
            String windUrl,
            int windWidth,
            int windHeight) {
		if(appSettingDto == null) {
				appSettingDto = new AppSettingDto(logPass, logFileExtension, title, windUrl, windWidth, windHeight);
		}else {
			//インスタンが重複している場合、エラーをスローする。キャッチ先：Main or SettingLoader
			throw new IllegalStateException();
		}	
	}
	//************
	// メソッド名：インスタンス取得処理
	// 処理内容：インスタンスが生成済かチェックして、返す。
	/************/
	public static AppSettingDto getInstance() {
		if(appSettingDto == null) {
			throw new IllegalStateException();
		}
		return appSettingDto;
	}
	
	//************
	// メソッド名：フィールド変数のGetter
	// 処理内容：各フィールド変数の中身を取得。
	/************/
	public String getLogPass() {
		return logPass;
	}
	public String getLogFileExtensionString() {
		return logFileExtensionString;
	}
	public String getWindUrl() {
		return windUrl;
	}
	public int getWindWidth() {
		return windWidth;
	}
	public int getWindHeight() {
		return windHeight;
	}
	public String getTitle() {
		return title;
	}

}

```

::: note warn
設定ファイルDtoは、アプリ起動時に一度しか生成しないので、Singletonパターンがメモリ効率も良くなるのではと考えました。

しかし、UTのソースを考えているときに、
「あれ、一つのソースファイルで複数のパターン試せないかも？」と思いました。
というのも、テスト実行の中で一つのインスタンスしか生成できないということは、パターンごとにインスタンスを生成する処理を動かしても、既にインスタンスが生成されているような状態になります。
※一応、パターン実行前に削除するようなリフレクション処理を挟めば良いらしいです。

しかし、今後の<font color=red>再利用性が悪い点</font>や<font color=red>UT自体を難しくする＝バグの温床になりやすいという点</font>
からSingletonをやめることにしました。
:::

ということで、
AppSettingDtoでSingletonパターンをやめる＝インスタンス生成処理と取出し処理の責任を別のクラスに渡す必要があるなと思いました。

:::note info
元々、Singletonパターンのために＝オブジェクトのインスタンスをstaticにしており、引数付きコンストラクタ呼び出しのためにstaticな生成処理を実装。
設定ファイルDtoにオブジェクトに関する責任を全て集約していました。
:::

というわけで、以下の2つにわけました。

``` AppSettingDto.java
package app.config;

/**
 * 設定ファイルのDtoクラス。
 * @author 
 * @version 1.1
 */
class AppSettingDto {
	
	/*
	 属性:タイトル、表示URL、ウィンドウ幅、ウィンドウ高さ
	*/
	private final String logPass;
	private final String logFileExtensionString;
	private final String title;
	private final String windUrl;
	private final int windWidth;
	private final int windHeight;

	//************
	// メソッド名：引数付きコンストラクタ
	// 処理内容：インスタンス生成用コンストラクタ、同パッケージのAppSettingFactoryのcreateInstace()から呼ぶ。
	/************/
	AppSettingDto(String logPass,
			              String logFileExtension,
			              String title,
			              String windUrl,
			              int windWidth,
			              int windHeight){
		this.logPass= logPass;
		this.logFileExtensionString = logFileExtension;
		this.title = title;
		this.windUrl = windUrl;
		this.windWidth = windWidth;
		this.windHeight = windHeight;
	}
	
	//************
	// メソッド名：フィールド変数のGetter
	// 処理内容：各フィールド変数の中身を取得。
	/************/
	public String getLogPass() {
		return logPass;
	}
	public String getLogFileExtensionString() {
		return logFileExtensionString;
	}
	public String getWindUrl() {
		return windUrl;
	}
	public int getWindWidth() {
		return windWidth;
	}
	public int getWindHeight() {
		return windHeight;
	}
	public String getTitle() {
		return title;
	}

}

```
::: note info
コンストラクタは、Factoryクラスのメソッドからでないと呼び出せないように、
パッケージプライベートにしています。
:::


``` AppSettingFactory.java

package app.config;

/**
 * 設定ファイルDtoのFactoryクラス。
 * @author 
 * @version 1.0
 */
class AppSettingFactory {
	/*
	 属性:設定ファイルDto
	*/
	private AppSettingDto appSettingDto ;
	
	//************
	// メソッド名：インスタンス取得処理
	// 処理内容：インスタンスが生成済かチェックして、返す。
	/************/
	AppSettingDto getInstance() {
		if(appSettingDto == null) {
			throw new IllegalStateException();
		}
		return appSettingDto;
	}
	
	//************
	// メソッド名：インスタンス生成メソッド
	// 処理内容：重複チェックをした後に、引数つきコンストラクタを呼び出す。
	/************/
	void createInstance(String logPass,
            String logFileExtension,
            String title,
            String windUrl,
            int windWidth,
            int windHeight) {
		//引数付きコンストラクタ呼び出し。
			appSettingDto = new AppSettingDto(logPass, logFileExtension, title, windUrl, windWidth, windHeight);
	}
}

```
::: note info
createInstanceメソッドの引数が流石に長すぎる気がすぎるので、設定ファイルの値をもつだけのDtoクラス（PropertiesDto）を用意した方が良いのか迷います。
とはいえ、

元々：
1. Loaderクラスで.properties読み込み
1. 「java.util.Properties」を使って、Key、Valueで変数に値を取出す
1. FactoryクラスのcreateInstanceに渡す

Propertiesファイル用のDtoを用意した場合：
1.  Loaderクラスで.properties読み込み
1.  「java.util.Properties」を使って、Key、ValueでPropertiesDtoに値を取出す
1.  GetterでFactoryクラスのcreateInstanceに渡す

程度の違いしかなく、PropertiesDtoも使い回すことがないので、直接渡そうと思います。
:::

### 最後に
ということで、一度設定ファイルDtoを作成するもUTのためのテストソースを作成しようとして、クラス設計まで戻りました。
反省点としては以下です。
・Singletonパターンのデメリットを理解していなかった。
※メモリの節約やインスタンスの状態が必ず一緒というメリットはあるが、密な結合となり、今後の拡張性やテストの難しさといったデメリットがある。
・単体テストのやり方の理解が浅かった。
※Factoryクラスは、他のDtoでも作成する必要があるので、テストソースのほとんどを使い回すことができ、工数削減につながる。

ここまでお付き合いありがとうございます。クラス設計書やクラス図などに修正がでましたが、ここには掲載するのはやめておこうと思います。
今回のようにちょこちょこ修正が入ると思いますので、完成したら最後にまとめてGithubなどで掲載しようと思います。
次からFactoryクラスのUTやります。
全然すすまん。