上一篇處理了基本的I/O傳輸,我們常常還要做些其它的事。可能要計數一下傳輸了多少個資料,過濾一下資料,或者是每1000條資料做一下日誌,又或者要看一下進行中什麼操作。既然輸入輸出已經分離,這些事變成在輸入輸出的協調代碼中簡單地插入一些邏輯。大部分協調代碼有類似的功能,可以放到標準的工具方法中,更方便使用。
第一個標準修飾器是一個過濾器。實現時我用到了Specification。
public interface Specification<T> { boolean test(T item);}
從上一篇可以看到最後的操作是
Inputs.text(source).transferTo(Outputs.text(destination));
要做其他事情只能對Output進行增強。因為sender和receiver都是通過他來調用的,同樣的需要對這兩個進行增強。
public class Filters { static class SpecificationOutputWrapper<T, ReceiverThrowableType extends Throwable> implements Output<T, ReceiverThrowableType> { final Output<T, ReceiverThrowableType> output; final Specification<T> specification; public SpecificationOutputWrapper(Output<T, ReceiverThrowableType> output, Specification<T> specification) { this.output = output; this.specification = specification; } public <SenderThrowableType extends Throwable> void receiveFrom(Sender<T, SenderThrowableType> sender) throws ReceiverThrowableType, SenderThrowableType { output.receiveFrom(new SpecificationSenderWrapper<T, SenderThrowableType>(sender, specification)); } } static class SpecificationSenderWrapper<T, SenderThrowableType extends Throwable> implements Sender<T, SenderThrowableType> { final Sender<T, SenderThrowableType> sender; final Specification<T> specification; public SpecificationSenderWrapper(Sender<T, SenderThrowableType> sender, Specification<T> specification) { this.sender = sender; this.specification = specification; } public <ReceiverThrowableType extends Throwable> void sendTo(Receiver<T, ReceiverThrowableType> receiver) throws ReceiverThrowableType, SenderThrowableType { sender.sendTo(new SpecificationReceiverWrapper<T, ReceiverThrowableType>(receiver, specification)); } } static class SpecificationReceiverWrapper<T, ReceiverThrowableType extends Throwable> implements Receiver<T, ReceiverThrowableType> { final Receiver<T, ReceiverThrowableType> receiver; final Specification<T> specification; public SpecificationReceiverWrapper(Receiver<T, ReceiverThrowableType> receiver, Specification<T> specification) { this.receiver = receiver; this.specification = specification; } public void receive(T item) throws ReceiverThrowableType { if(specification.test(item)) { receiver.receive(item); } } public void finished() throws ReceiverThrowableType { receiver.finished(); } } public static <T, ReceiverThrowableType extends Throwable> Output<T, ReceiverThrowableType> filter(Specification<T> specification, final Output<T, ReceiverThrowableType> output) { return new SpecificationOutputWrapper<T, ReceiverThrowableType>(output, specification); }}
測試代碼:
public class Demo_Intercept_FilterLine { public static void main(String[] args) throws IOException { File source = new File("in"); File destination = new File("out"); Input<String, IOException> input = Inputs.text(source); Output<String, IOException> output = Outputs.text(destination); Specification<String> specification = new Specification<String>() { public boolean test(String item) { if(item.trim().length() == 0) return false; // 過濾空行 return true; } }; input.transferTo(Filters.filter(specification, output)); }}
第二個常見的操作是把資料從一個類型映射到另一個類型。就是處理要Input和Output的資料類型不同,要有方法把輸入資料類型映射成輸出的資料類型。下面例子的把String映射成JSONObject,先定義轉換方法:
public interface Function<From, To> { /** * @return return the transformed data. {@code null} to indicate ignore the input data. */ To map(From from);}
剩下的基本和上面的類似
public class FunctionFilter { private FunctionFilter(){} static class FunctionOutputWrapper<From, To, ReceiverThrowableType extends Throwable> implements Output<From, ReceiverThrowableType> { final Output<To, ReceiverThrowableType> output; final Function<From, To> function; public FunctionOutputWrapper(Output<To, ReceiverThrowableType> output, Function<From, To> function) { this.output = output; this.function = function; } public <SenderThrowableType extends Throwable> void receiveFrom(Sender<From, SenderThrowableType> sender) throws ReceiverThrowableType, SenderThrowableType { output.receiveFrom(new FunctionSenderWrapper<From, To, SenderThrowableType>(sender, function)); } } static class FunctionSenderWrapper<From, To, SenderThrowableType extends Throwable> implements Sender<To, SenderThrowableType> { final Sender<From, SenderThrowableType> sender; final Function<From, To> function; public FunctionSenderWrapper(Sender<From, SenderThrowableType> sender, Function<From, To> function) { this.sender = sender; this.function = function; } public <ReceiverThrowableType extends Throwable> void sendTo(Receiver<To, ReceiverThrowableType> receiver) throws ReceiverThrowableType, SenderThrowableType { sender.sendTo(new FunctionReceiverWrapper<From, To, ReceiverThrowableType>(receiver, function)); } } static class FunctionReceiverWrapper<From, To, ReceiverThrowableType extends Throwable> implements Receiver<From, ReceiverThrowableType> { final Receiver<To, ReceiverThrowableType> receiver; final Function<From, To> function; public FunctionReceiverWrapper(Receiver<To, ReceiverThrowableType> receiver, Function<From, To> function) { this.receiver = receiver; this.function = function; } public void receive(From item) throws ReceiverThrowableType { receiver.receive(function.map(item)); } public void finished() throws ReceiverThrowableType { receiver.finished(); } } public static <From, To, ReceiverThrowableType extends Throwable> Output<From, ReceiverThrowableType> filter(Function<From, To> function, final Output<To, ReceiverThrowableType> output) { return new FunctionOutputWrapper<From, To, ReceiverThrowableType>(output, function); }}
測試代碼:
public class Demo_Intercept_CountLine { public static void main(String[] args) throws IOException { File source = new File("in"); File destination = new File("out"); final AtomicInteger count = new AtomicInteger(); Input<String, IOException> input = Inputs.text(source); Output<String, IOException> output = Outputs.text(destination); Function<String, String> function = new Function<String, String>() { public String map(String from) { count.incrementAndGet(); return from; } }; input.transferTo(FunctionFilter.filter(function, output)); System.out.println("Counter: " + count.get()); }}
轉載自:https://github.com/oldratlee/io-api/wiki/generic-io-api-in-java-and-api-design