剩下的就是配置包含实现的 JAR 文件,让 ServiceLoader 能识别 — 这可能会非常棘手。JDK 想要 JAR 文件有一个 META-INF/services 目录,它包含一个文本文件,其文件名与接口类名完全匹配 — 本例中是 META-INF/services/IPersonalServant。接口类名的内容是实现的名称,每行一个,如清单 5:
清单 5. META-INF/services/IPersonalServant
Jeeves # comments are OK |
幸运的是,Ant 构建系统(自 1.7.0 以来)包含一个对 jar 任务的服务标签,让这相对容易,见清单 6:
清单 6. Ant 构建的 IPersonalServant
<target name="serviceloader" depends="build"> <jar destfile="misc.jar" basedir="./classes"> <service type="IPersonalServant"> <provider classname="Jeeves" /> </service> </jar> </target> |
这里,很容易调用 IPersonalServant,让它执行命令。然而,解析和执行这些命令可能会非常棘手。这又是另一个 “小线头”。
3. Scanner
有无数 Java 工具能帮助您构建解析器,很多函数语言已成功构建解析器函数库(解析器选择器)。但如果要解析的是逗号分隔值文件,或空格分隔文本文件,又怎么办呢?大多数工具用在此处就过于隆重了,而 String.split() 又不够。(对于正则表达式,请记住一句老话:“ 您有一个问题,用正则表达式解决。那您就有两个问题了。”)
Java 平台的 Scanner 类会是这些类中您最好的选择。以轻量级文本解析器为目标,Scanner 提供了一个相对简单的 API,用于提取结构化文本,并放入强类型的部分。想象一下,如果您愿意,一组类似 DSL 的命令(源自 Terry Pratchett Discworld 小说)排列在文本文件中,如清单 7:
清单 7. Igor 的任务
fetch 1 head fetch 3 eye fetch 1 foot attach foot to head attach eye to head admire |
您,或者是本例中称为 Igor的私仆,能轻松使用 Scanner 解析这组违法命令,如清单 8 所示:
清单 8. Igor 的任务,由 Scanner 解析
import java.io.*; import java.util.*; public class Igor implements IPersonalServant { public boolean can(String cmd) { if (cmd.equals("fetch body parts")) return true; if (cmd.equals("attach body parts")) return true; else return false; } public void process(File commandFile) throws FileNotFoundException { Scanner scanner = new Scanner(commandFile); // Commands come in a verb/number/noun or verb form while (scanner.hasNext()) { String verb = scanner.next(); if (verb.equals("fetch")) { int num = scanner.nextInt(); String type = scanner.next(); fetch (num, type); } else if (verb.equals("attach")) { String item = scanner.next(); String to = scanner.next(); String target = scanner.next(); attach(item, target); } else if (verb.equals("admire")) { admire(); } else { System.out.println("I don't know how to " + verb + ", marthter."); } } } public void fetch(int number, String type) { if (parts.get(type) == null) { System.out.println("Fetching " + number + " " + type + (number > 1 ? "s" : "") + ", marthter!"); parts.put(type, number); } else { System.out.println("Fetching " + number + " more " + type + (number > 1 ? "s" : "") + ", marthter!"); Integer currentTotal = parts.get(type); parts.put(type, currentTotal + number); } System.out.println("We now have " + parts.toString()); } public void attach(String item, String target) { System.out.println("Attaching the " + item + " to the " + target + ", marthter!"); } public void admire() { System.out.println("It'th quite the creathion, marthter"); } private Map<String, Integer> parts = new HashMap<String, Integer>(); } |
【福利】填问卷送精选测试礼包+接口测试课程!为测试行业做点事!