职责链(Chain of Responsibility)设计模式先创建了一批用于解决目标问题的不同方法,然后将它们连成一条“链”。当一个请求到达时,会顺着这条链传递下去,直到遇到链上某个可以处理该请求的方法。
可以很容易地用常量特定方法实现一条简单的职责链。考虑一个邮局模型,它对每一封邮件都会尝试用最常见的方式来处理,(如果行不通)并不断尝试别的方式,直到该邮件最终被视为“死信”(无法投递)。每种尝试都可以看作一个策略(另一种设计模式),而整个策略列表放在一起就是一条职责链。
我们从一封邮件开始说起。它所有的重要特征都可以用枚举来表达。由于 Mail 对象是随机创建的,想要减小一封邮件的 GeneralDelivery 被赋予 YES 的可能性,最简单的方法是创建更多的非 YES 的实例,因此枚举的定义一开始可能看起来有点好笑。
在 Mail 中,你会看到 randomMail() 方法,用来随机创建测试邮件。generator() 方法生成了一个 Iterator 对象,它使用 randomMail() 方法来生成一定数量的 Mail 对象,每通过迭代器调用一次 next() 就会生成一个。这种结构允许通过调用 Mail.generator() 方法实现 for-in 循环的简单创建能力。
PostOffice.java
import enums.TEST0003.Enums;
import java.util.Iterator;
class Mail {
// The NO's reduce probability of random selection:
enum GeneralDelivery {YES, NO1, NO2, NO3, NO4, NO5}
enum Scannability {UNSCANNABLE, YES1, YES2, YES3, YES4}
enum Readability {ILLEGIBLE, YES1, YES2, YES3, YES4}
enum Address {INCORRECT, OK1, OK2, OK3, OK4, OK5, OK6}
enum ReturnAddress {MISSING, OK1, OK2, OK3, OK4, OK5}
GeneralDelivery generalDelivery;
Scannability scannability;
Readability readability;
Address address;
ReturnAddress returnAddress;
static long counter = 0;
long id = counter++;
@Override
public String toString() {
return "Mail " + id;
}
public String details() {
return toString() +
", General Delivery: " + generalDelivery +
", Address Scannability: " + scannability +
", Address Readability: " + readability +
", Address Address: " + address +
", Return address: " + returnAddress;
}
// Generate test Mail:
public static Mail randomMail() {
Mail m = new Mail();
m.generalDelivery = Enums.random(GeneralDelivery.class);
m.scannability = Enums.random(Scannability.class);
m.readability = Enums.random(Readability.class);
m.address = Enums.random(Address.class);
m.returnAddress = Enums.random(ReturnAddress.class);
return m;
}
public static Iterable<Mail> generator(final int count) {
return new Iterable<Mail>() {
int n = count;
@Override
public Iterator<Mail> iterator() {
return new Iterator<Mail>() {
@Override
public boolean hasNext() {
return n-- > 0;
}
@Override
public Mail next() {
return randomMail();
}
@Override
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
}
};
}
}
public class PostOffice {
enum MailHandler {
GENERAL_DELIVERY {
@Override
boolean handle(Mail m) {
switch (m.generalDelivery) {
case YES:
System.out.println("Using general delivery for " + m);
return true;
default:
return false;
}
}
},
MACHINE_SCAN {
@Override
boolean handle(Mail m) {
switch (m.scannability) {
case UNSCANNABLE:
return false;
default:
switch (m.address) {
case INCORRECT:
return false;
default:
System.out.println("Delivering " + m + " automatically");
return true;
}
}
}
},
VISUAL_INSPECTION {
@Override
boolean handle(Mail m) {
switch (m.readability) {
case ILLEGIBLE:
return false;
default:
switch (m.address) {
case INCORRECT:
return false;
default:
System.out.println("Delivering " + m + " normally");
return true;
}
}
}
},
RETURN_TO_SENDER {
@Override
boolean handle(Mail m) {
switch (m.returnAddress) {
case MISSING:
return false;
default:
System.out.println("Returning " + m + " to sender");
return true;
}
}
};
abstract boolean handle(Mail m);
}
static void handle(Mail m) {
for (MailHandler handler : MailHandler.values()) {
if (handler.handle(m)) {
return;
}
}
System.out.println(m + " is a dead letter");
}
public static void main(String[] args) {
for (Mail mail : Mail.generator(10)) {
System.out.println(mail.details());
handle(mail);
System.out.println("*****");
}
}
}
运行结果如下:
职责链模式的作用体现在了 MailHandler枚举中,枚举的定义顺序则决定了各个策略在每封邮件上被应用的顺序。该模式会按顺序尝试应用每个策略,直到某个策略执行成功,或者全部策略都执行失败(即邮件无法投递)