Java I/O汎用api設計(二)
8174 ワード
前回は基本的なI/O転送を処理しましたが、私たちはいつも他のことをしなければなりません.何個のデータが転送されたかをカウントしたり、データをフィルタしたり、1000個のデータごとにログを作ったり、どのような操作が行われているかを見たりすることができます.入出力が分離されている以上、これらは入出力の協調コードに簡単に論理を挿入することになる.ほとんどのコーディネートコードには似たような機能があり、標準的なツールメソッドに入れることができ、より使いやすいです.
最初の標準修飾器はフィルタです.実装時にSpecificationを使いました.
前回から見た最後の操作は
テストコード:
2つ目の一般的な操作は、データを1つのタイプから別のタイプにマッピングすることです.つまり、InputとOutputのデータ型の違いを処理するには、入力データ型を出力データ型にマッピングする方法が必要です.次の例ではStringをJSOnObjectにマッピングし、変換方法を定義します.
テストコード:
転載先:https://github.com/oldratlee/io-api/wiki/generic-io-api-in-java-and-api-design
最初の標準修飾器はフィルタです.実装時にSpecificationを使いました.
public interface Specification<T> {
boolean test(T item);
}
前回から見た最後の操作は
Inputs.text(source).transferTo(Outputs.text(destination));
他のことをするにはOutputを強化するしかありません.senderとreceiverは彼を通じて呼び出されるので、同じようにこの2つを強化する必要があります.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));
}
}
2つ目の一般的な操作は、データを1つのタイプから別のタイプにマッピングすることです.つまり、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