辞書を片手に~PatternResponderの作成(6) | Pythonでなんか作ってみる

辞書を片手に~PatternResponderの作成(6)

ToDoリスト
・loadDictionary()とloadDictionaryResponse()で、同じファイル読み込みを繰り返している


これを解消するために、上記2メソッド結果をインスタンス変数に保存する形にする。

そのため、まずはメソッドをインスタンスメソッドに変更する。


public void testLoadDictionary() throws FileNotFoundException {
PatternResponder responder = new PatternResponder();

assertEquals(new Pattern[] { Pattern.compile("今日はさむいね"),
Pattern.compile("チョコたべたい"), Pattern.compile("きのう10円ひろった") },
responder
.loadDictionary(new FileReader("dics/pattern.txt")));
}

public void testLoadDictionaryResponse() throws FileNotFoundException {
PatternResponder responder = new PatternResponder();

assertEquals(new String[]{"さむくないよ","食べれば","いいね"},
responder
.loadDictionaryResponse(new FileReader("dics/pattern.txt")));
}

staticメソッドをインスタンスメソッドの形式で呼び出しても問題ないのでテストはGreenのままである。

本体の方をインスタンスメソッドに変更する。

これは、staticを取るだけだ。テスト実行。Green。


patternsとresponsesをインスタンス変数にとり、コンストラクタで初期化しようと思ったが、FileReaderがこの時点では入手できないことに気づいた。コンストラクタの引数で渡す形に変更して実現することにする。当然テスト側もだ。


public class PatternResponder {

private Pattern[] patterns;
private String[] responses;

public PatternResponder() {
patterns = this.loadDictionary(null);
responses = this.loadDictionaryResponse(null);
}

こっちはテスト。


public void testLoadDictionary() throws FileNotFoundException {
PatternResponder responder = new PatternResponder(new FileReader("dics/pattern.txt"));

assertEquals(new Pattern[] { Pattern.compile("今日はさむいね"),
Pattern.compile("チョコたべたい"), Pattern.compile("きのう10円ひろった") },
responder
.loadDictionary(new FileReader("dics/pattern.txt")));
}

public void testLoadDictionaryResponse() throws FileNotFoundException {
PatternResponder responder = new PatternResponder(new FileReader("dics/pattern.txt"));

assertEquals(new String[]{"さむくないよ","食べれば","いいね"},
responder
.loadDictionaryResponse(new FileReader("dics/pattern.txt")));
}

どんどん進む。loadDictionaryとloadDictionaryResponseの中身をコンストラクタに移して、loadDictionaryとloadDictionaryResponseはそれぞれインスタンス変数を返すことにする。


public PatternResponder(FileReader reader) {
String[] patternStrings = splitPatternAndResponse(RandomResponder.loadDictionary(reader), 0);

patterns = new Pattern[patternStrings.length];

for (int index=0;index < patterns.length; index++) {
patterns[index] = Pattern.compile(patternStrings[index]);
}
patterns = this.loadDictionary(reader);
responses = splitPatternAndResponse(RandomResponder.loadDictionary(reader), 1);
}

public Pattern[] loadDictionary(FileReader reader) {
return patterns;
}

public String[] loadDictionaryResponse(FileReader reader) {
return responses;
}

テスト実行。Red!!あれ?何か壊したか?下線部が余計だったか。削除して再テスト。やっぱりRedだ。

テスト結果を見ると、testLoadDictionaryResponse()で取得した応答例の数が異なっていることになっている。


junit.framework.AssertionFailedError: expected:<3> but was:<0>
at junit.framework.Assert.fail(Assert.java:47)

あ、そうか。readerを初期化していないから、patternの方を取得した段階で、ファイルの終わりに行ってしまっているんだな?

こう、変える。


public PatternResponder(FileReader reader) {
String[] loadStrings = RandomResponder.loadDictionary(reader);
String[] patternStrings = splitPatternAndResponse(loadStrings, 0);

patterns = new Pattern[patternStrings.length];

for (int index=0;index < patterns.length; index++) {
patterns[index] = Pattern.compile(patternStrings[index]);
}
responses = splitPatternAndResponse(loadStrings, 1);
}

これでテスト実行。Green。しかも、。ファイルの読み込みは一度だけだ。

しかし、いまいち納得できない。

splitPatternAndResponseを(Eclipseのリファクタリング機能で)inline展開してみる。


public PatternResponder(FileReader reader) {
String[] loadStrings = RandomResponder.loadDictionary(reader);
String[] responses1 = new String[loadStrings.length];

for (int index1=0;index1 < loadStrings.length; index1++) {
responses1[index1] = loadStrings[index1].split("\t")[0];
}
String[] patternStrings = responses1;

patterns = new Pattern[patternStrings.length];

for (int index=0;index < patterns.length; index++) {
patterns[index] = Pattern.compile(patternStrings[index]);
}
String[] responses2 = new String[loadStrings.length];

for (int index=0;index < loadStrings.length; index++) {
responses2[index] = loadStrings[index].split("\t")[1];
}
responses = responses2;
}

responses1とresponses2を無くして、patternStringとresponsesを直接使うようにする。

inline展開がうまくいかなかったので、手作業。


public PatternResponder(FileReader reader) {
String[] loadStrings = RandomResponder.loadDictionary(reader);
String[] patternStrings = new String[loadStrings.length];

for (int index1=0;index1 < loadStrings.length; index1++) {
patternStrings[index1] = loadStrings[index1].split("\t")[0];
}

patterns = new Pattern[patternStrings.length];

for (int index=0;index < patterns.length; index++) {
patterns[index] = Pattern.compile(patternStrings[index]);
}
String[] responses = new String[loadStrings.length];

for (int index=0;index < loadStrings.length; index++) {
responses[index] = loadStrings[index].split("\t")[1];
}

}

テスト実行。またまた、Red。勢い余ったか。Undoして一つずつ変更する。


まずは、responses2の部分だけ。Green。そうか。responsesに置き換えたときに新たに宣言してしまっている。

この感じでpatternStringsへも置き換える。Green。

配列の大きさは結局loadString.lengthなので、newを最初に移動して、ループをまとめる。


public PatternResponder(FileReader reader) {
String[] loadStrings = RandomResponder.loadDictionary(reader);
String[] patternStrings = new String[loadStrings.length];
patterns = new Pattern[patternStrings.length];
responses = new String[loadStrings.length];

for (int index=0;index < loadStrings.length; index++) {
patternStrings[index] = loadStrings[index].split("\t")[0];
patterns[index] = Pattern.compile(patternStrings[index]);
responses[index] = loadStrings[index].split("\t")[1];
}
}

patternStringsは不要に見えるので削除する。

まら、Eclipseのinlineがうまく効かない。手作業である。


public PatternResponder(FileReader reader) {
String[] loadStrings = RandomResponder.loadDictionary(reader);

patterns = new Pattern[loadStrings.length];
responses = new String[loadStrings.length];

for (int index=0;index < loadStrings.length; index++) {
patterns[index] = Pattern.compile(loadStrings[index].split("\t")[0]);
responses[index] = loadStrings[index].split("\t")[1];
}
}

テスト実行。よしよし。Green。

splitを2回実施しているのが無駄に見えるので、一時変数を用いることにする。


public PatternResponder(FileReader reader) {
String[] loadStrings = RandomResponder.loadDictionary(reader);

patterns = new Pattern[loadStrings.length];
responses = new String[loadStrings.length];

for (int index=0;index < loadStrings.length; index++) {
String[] patternAndResponses=loadStrings[index].split("\t");
patterns[index] = Pattern.compile(patternAndResponses[0]);
responses[index] = patternAndResponses[1];
}
}

これで、見た感じ重複はなさそうだ。また、機能の追加に移るか。