辞書を片手に~PatternResponderの作成(9)
さて「マッチするパターンがなかったときは、ランダム辞書からランダムに選択した応答を返す」に取り掛かるわけだが。
当然テストを作る。
public class PatternResponderTest extends ResponderTest {
public void testRandomResponse() throws FileNotFoundException {
PatternResponder resp = new PatternResponder("pattern", new FileReader("dics/pattern.txt"));
assertEquals("今日はさむいね",resp.response("今日はさむくないね"));
assertEquals("チョコたべたい",resp.response("今日はさむくないね"));
assertEquals("きのう10円ひろった",resp.response("今日はさむくないね"));
}
}
パターンにないメッセージを送ったら、ランダム辞書の一番目から順に応答を返すテストである。
念のためテストを実行。Red。
PatternResponderのコンストラクタがRandomを受け取るようになっていないので、さっき作ったFakeRandomIntを使用できない。コンストラクタに追加する。
public PatternResponder(String name, Reader reader) {...}
public PatternResponder(String name, Reader reader,Random rnd) {..}
テストの方にもFakeRandomIntを追加するが、当然これでもテストは通らない。PatternResponderは元々Randomを使用していないのだからである。
それでは、早速コンストラクタで手に入れたRandomを使用してランダム辞書から応答を返すわけだが、『ランダム辞書から応答を返す』というのはどういうことだろうか?
それは、RandomResponderのように振舞うということである。
では、RandomResponderのように振舞うのに一番簡単な方法はなんだろうか?
それは、RandomResponderのインスタンスを保持しておいて、必要なときに処理を委譲するというのが簡単なのでは無いだろうか?
そのように処理を追加する。
まずは、コンストラクタでインスタンス変数にRandomResponderのインスタンスを保持する。
public class PatternResponder extends Responder {
private Responder randomResponder;
public PatternResponder(String name, Reader reader,Random rnd) {
super(name);
randomResponder = new RandomResponder(name,rnd);
...
}
次に、今まで一致するパターンが無いときに空文字列を返していたところの処理をRandomResponderに委譲する。
public String response(String msg) {
for (int index=0;index < patterns.length; index++) {
Matcher m = patterns[index].matcher(msg);
if (m.find()) {
return responses[index];
}
}
return randomResponder.response(msg);
}
テスト実行。Green!!!一発完動である。
ここで気づいたのだが、RandomResponderは辞書のファイル名をコンストラクタで受け取るのに対し、PatternResponderは辞書ファイル自体(Reader)を受け取る。
PatternResponderの異常データ系テストでそれを利用してファイルを作らずにテストケースを作成したように、PatternReponderの形式の方が優れているように思える。
ToDoに追加しておく。
ToDoリスト
・正規表現を使ってパターンに反応するResponder(以下の仕様を満たす)
・1つのパターンに対して応答例は「|」で区切って複数設定でき、いずれかがランダムに選択される
・マッチするパターンがなかったときは、ランダム辞書からランダムに選択した応答を返す
・応答例の中に「%match」という文字列があれば、パターンにマッチした文字列と置き換えられる
・RandomResponderのコンストラクタでファイル名(String)でなくファイル(Reader)を受け取るようにする