ジョブコントローラ(ラムダ式)
リスト3のプログラムでAbstractFactoryの役割を担っている Supplier インタフェースは、先にも述べたように、関数型インタフェースです。したがって、Supplier インタフェースのインスタンスは、BackupJobFactory クラスのようなクラスを介さずに、ラムダ式で直接生成できます。このように変更したプログラムは、図7のような構成になります。
ラムダ式を用いてリスト3を書き換えたプログラムを、リスト4に掲げます。リスト3からの変更点は「★」印で示しています。
import java.util.List;
import java.util.ArrayList;
import java.util.function.Supplier;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
/**
* ジョブ定義 (Client).
*/
class JobDefinition<J extends Job> {
/** ジョブのファクトリ. */
private final Supplier<? extends J> jobMaker;
/** オブザーバ一式. */
private final List<JobObserver<? super J>> observers = new ArrayList<>();
public JobDefinition(Supplier<? extends J> jobMaker) {
this.jobMaker = jobMaker;
}
/** オブザーバを登録. */
public void addObserver(JobObserver<? super J> observer) {
this.observers.add(observer);
}
/** ジョブを作成、実行. */
public final void execute() {
J job = this.jobMaker.get();
notifyObservers(job);
job.execute();
notifyObservers(job);
}
/** オブザーバにジョブの状態を通知. */
private void notifyObservers(J job) {
for (JobObserver<? super J> observer : this.observers) {
observer.update(job);
}
}
}
/**
* ジョブ (AbstractProduct).
*/
abstract class Job {
/** ジョブの状態. */
enum Status { UNFINISHED, FINISHED }
/** ジョブの状態. */
private Status status;
Job() {
this.status = Status.UNFINISHED;
}
/** ジョブの状態を戻す. */
final Status getStatus() {
return this.status;
}
/** ジョブが完了していたらtrueを戻す. */
final boolean isFinished() {
return this.status == Status.FINISHED;
}
/** ジョブを実行. */
final void execute() {
run();
this.status = Status.FINISHED;
}
/** ジョブの処理の内容を実装. */
abstract void run();
}
/**
* ジョブ実行のオブザーバ.
*/
@FunctionalInterface
interface JobObserver<J extends Job> {
void update(J job);
}
public class JobController4 {
/**
* データベースをバックアップするジョブ (ConcreteProduct).
*/
static class BackupJob extends Job {
/** バックアップファイルの名前. */
private final String fileName;
BackupJob(String fileName) {
this.fileName = fileName;
}
/** バックアップファイルの名前を戻す. */
String getFileName() {
return this.fileName;
}
@Override
void run() {
System.out.printf("$ pg_dumpall >%s%n", this.fileName);
}
}
/** バックアップファイル名のフォーマッタ. */
private static final DateTimeFormatter FILE_NAME_FORMATTER
= DateTimeFormatter.ofPattern("'/backup/'yyyy_MM_dd'.sql'");
public static void main(String[] args) {
// バックアップジョブの生成をラムダ式で登録★
JobDefinition<BackupJob> backupJobDefinition = new JobDefinition<>(() -> {
LocalDate startDate = LocalDate.now();
String fileName = startDate.format(FILE_NAME_FORMATTER);
return new BackupJob(fileName);
});
// バックアップジョブの状態をログ出力するオブザーバを登録
backupJobDefinition.addObserver(backupJob -> {
System.out.printf("[INFO] バックアップ: %s ステータス: %s%n",
backupJob.getFileName(), backupJob.getStatus());
});
// バックアップジョブ完了をメール通知するオブザーバを登録
String admin = "eva.lu.ator@example.org";
backupJobDefinition.addObserver(backupJob -> {
if (backupJob.isFinished()) {
System.out.printf("$ echo '%sへのバックアップ完了!' | mail -s 'バックアップ通知' %s%n",
backupJob.getFileName(), admin);
}
});
// バックアップジョブ実行
backupJobDefinition.execute();
}
}
プログラムの実行結果は、リスト3とまったく同一です。
[INFO] バックアップ: /backup/2015_03_12.sql ステータス: UNFINISHED $ pg_dumpall >/backup/2015_03_12.sql [INFO] バックアップ: /backup/2015_03_12.sql ステータス: FINISHED $ echo '/backup/2015_03_12.sqlへのバックアップ完了!' | mail -s 'バックアップ通知' eva.lu.ator@example.org

