ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
### 使用 enum 的职责链 在职责链(Chain of Responsibility)设计模式中,程序员以多种不同的方式来解决一个问题,然后将它们链接在一起。当一个请求到来时,它遍历这个链,直到链中的某个解决方案能够处理该请求。 通过常量相关的方法,我们可以很容易地实现一个简单的职责链。我们以一个邮局的模型为例。邮局需要以尽可能通用的方式来处理每一封邮件,并且要不断尝试处理邮件,直到该邮件最终被确定为一封死信。其中的每一次尝试可以看作为一个策略(也是一个设计模式),而完整的处理方式列表就是一个职责链。 我们先来描述一下邮件。邮件的每个关键特征都可以用 enum 来表示。程序将随机地生成 Mail 对象,如果要减小一封邮件的 GeneralDelivery 为 YES 的概率,那最简单的方法就是多创建几个不是 YES 的 enum 实例,所以 enum 的定义看起来有点古怪。 我们看到 Mail 中有一个 randomMail() 方法,它负责随机地创建用于测试的邮件。而 generator() 方法生成一个 Iterable 对象,该对象在你调用 next() 方法时,在其内部使用 randomMail() 来创建 Mail 对象。这样的结构使程序员可以通过调用 Mail.generator() 方法,很容易地构造出一个 foreach 循环: ```java // enums/PostOffice.java // Modeling a post office import java.util.*; import onjava.*; 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 Scanability: " + 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("*****"); } } } ``` 输出为: ``` Mail 0, General Delivery: NO2, Address Scanability: UNSCANNABLE, Address Readability: YES3, Address Address: OK1, Return address: OK1 Delivering Mail 0 normally ***** Mail 1, General Delivery: NO5, Address Scanability: YES3, Address Readability: ILLEGIBLE, Address Address: OK5, Return address: OK1 Delivering Mail 1 automatically ***** Mail 2, General Delivery: YES, Address Scanability: YES3, Address Readability: YES1, Address Address: OK1, Return address: OK5 Using general delivery for Mail 2 ***** Mail 3, General Delivery: NO4, Address Scanability: YES3, Address Readability: YES1, Address Address: INCORRECT, Return address: OK4 Returning Mail 3 to sender ***** Mail 4, General Delivery: NO4, Address Scanability: UNSCANNABLE, Address Readability: YES1, Address Address: INCORRECT, Return address: OK2 Returning Mail 4 to sender ***** Mail 5, General Delivery: NO3, Address Scanability: YES1, Address Readability: ILLEGIBLE, Address Address: OK4, Return address: OK2 Delivering Mail 5 automatically ***** Mail 6, General Delivery: YES, Address Scanability: YES4, Address Readability: ILLEGIBLE, Address Address: OK4, Return address: OK4 Using general delivery for Mail 6 ***** Mail 7, General Delivery: YES, Address Scanability: YES3, Address Readability: YES4, Address Address: OK2, Return address: MISSING Using general delivery for Mail 7 ***** Mail 8, General Delivery: NO3, Address Scanability: YES1, Address Readability: YES3, Address Address: INCORRECT, Return address: MISSING Mail 8 is a dead letter ***** Mail 9, General Delivery: NO1, Address Scanability: UNSCANNABLE, Address Readability: YES2, Address Address: OK1, Return address: OK4 Delivering Mail 9 normally ***** ``` 职责链由 enum MailHandler 实现,而 enum 定义的次序决定了各个解决策略在应用时的次序。对每一封邮件,都要按此顺序尝试每个解决策略,直到其中一个能够成功地处理该邮件,如果所有的策略都失败了,那么该邮件将被判定为一封死信。