リスト2は、Chain of Responsibilityパターンの中核となるApprover(承認者)クラスです。Approverクラスでは、このデザインパターンにおける既知のエンティティがHandlerとして表現されています。これは一般に抽象クラスであり、具体的には、この例で実装することに決めたManager、VicePresident、CEO(リスト3を参照)の3種類のハンドラサブタイプのいずれかを表します。この他にAutoRejectHandlerも存在します。このタイプの承認者は何もかも拒否します。
クライアントは、handleメソッドを用いて、ExpenseReportオブジェクトをApproverへ送ります。handleメソッドのコードでは報告書の転送と承認のどちらを行うかが決定されます。報告書が転送されるのは、承認者にそれを処置する権限がない(具体的には金額が大きすぎるか、海外旅行の決済が許可されていない)場合と、承認者が不在の場合です。
public class Approver {
private Approver nextApprover;
private int dollarLimit;
private boolean isOutOfOffice;
private boolean canApproveInternational;
private final String name;
public Approver(String name, boolean canApproveInternational,
int dollarLimit) {
this.name = name;
this.canApproveInternational = canApproveInternational;
this.dollarLimit = dollarLimit;
}
public String getName() {
return name;
}
public void handle(ExpenseReport report) {
if (!canApprove(report) || isOutOfOffice())
nextApprover.handle(report);
else
report.approve(this);
}
private boolean canApprove(ExpenseReport report) {
return report.getTotalDollarAmount() <=
getDollarLimit() &&
(canApproveInternational() ||
!report.isInternationalTravel());
}
public void setNextApprover(Approver approver) {
nextApprover = approver;
}
public boolean isOutOfOffice() {
return isOutOfOffice;
}
public void setOutOfOffice(boolean isOutOfOffice) {
this.isOutOfOffice = isOutOfOffice;
}
public int getDollarLimit() {
return dollarLimit;
}
public boolean canApproveInternational() {
return canApproveInternational;
}
public void setCanApproveInternational(boolean
canApproveInternational) { this.canApproveInternational =
canApproveInternational;
}
}
Approverの各サブクラスでは、承認の詳細な制約が定義されます。管理者(Manager)が承認できる限度額は5,000ドルで、一部の管理者は海外旅行も承認できます。副社長(VicePresident)が承認できる限度額は100,000ドルで、すべての海外旅行を承認できます。CEOは、不在でない限り、何もかも承認できます。CEOが不在の場合、経費報告書は残念ながら自動的にAutoRejectHandlerへ送られます。
public class Manager extends Approver {
private static final int APPROVAL_LIMIT = 5000;
public Manager(String name, boolean canApproveInternational) {
super(name, canApproveInternational, APPROVAL_LIMIT);
}
}
public class VicePresident extends Approver {
private static final int APPROVAL_LIMIT = 100000;
public VicePresident(String name) {
super(name, true, APPROVAL_LIMIT);
}
}
public class CEO extends Approver {
private static final int APPROVAL_LIMIT = Integer.MAX_VALUE;
public CEO(String name) {
super(name, true, APPROVAL_LIMIT);
setNextApprover(new AutoRejectHandler());
}
}
public class AutoRejectHandler extends Approver {
public AutoRejectHandler() {
super("auto-reject", false, 0);
}
@Override
public void handle(ExpenseReport report) {
report.reject();
}
}
