リスト1に示すCommandクラスは、ProcessBuilderオブジェクトと、そのオブジェクトが作成するProcessオブジェクトとのやり取りを単純化するファサードです。
import java.io.*;
public class Command {
private String[] command;
private Process process;
private StringBuilder output = new StringBuilder();
private StringBuilder errorOutput = new StringBuilder();
public Command(String... command) {
this.command = command;
}
public void execute() throws Exception {
ProcessBuilder processBuilder =
new ProcessBuilder(command);
process = processBuilder.start();
collectOutput();
collectErrorOutput();
process.waitFor();
}
private void collectErrorOutput() {
Runnable runnable = new Runnable() {
public void run() {
try {
collectOutput(process.getErrorStream(),
errorOutput);
}
catch (IOException e) {
errorOutput.append(e.getMessage());
}
}
};
new Thread(runnable).start();
}
private void collectOutput() {
Runnable runnable = new Runnable() {
public void run() {
try {
collectOutput(process.getInputStream(), output);
}
catch (IOException e) {
output.append(e.getMessage());
}
}
};
new Thread(runnable).start();
}
private void collectOutput(InputStream inputStream,
StringBuilder collector) throws IOException {
BufferedReader reader = null;
try {
reader =
new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null)
collector.append(line);
}
finally {
reader.close();
}
}
public String getOutput() throws IOException {
return output.toString();
}
public String getErrorOutput() throws IOException {
return errorOutput.toString();
}
}
このCommandクラス内のProcessBuilderに関連するコードは、それほど複雑ではありません。とはいえ、1つのコマンドを実行して結果を取得するだけならば、できればもっと簡単に済ませたいところです。Commandクラスを使用すれば、話はずっと簡単になります。
Command command = new Command("dir", "/");
command.execute();
System.out.println(command.getOutput());
System.out.println(command.getErrorOutput());
Commandクラスのコンストラクタは、各コマンドラインパラメータを文字配列内の独立した文字列として受け取ります。
ファサードは、オブジェクト指向設計における、情報隠蔽の概念の中核を占めるものです。ProcessBuilderクラスとProcessクラスは実装の詳細であり、Commandクラスというインターフェースによって、こうした詳細を「コマンドの実行」と「出力の取得」という抽象レベルまで単純化しています。
