Java I/O汎用api設計(二)

8174 ワード

前回は基本的なI/O転送を処理しましたが、私たちはいつも他のことをしなければなりません.何個のデータが転送されたかをカウントしたり、データをフィルタしたり、1000個のデータごとにログを作ったり、どのような操作が行われているかを見たりすることができます.入出力が分離されている以上、これらは入出力の協調コードに簡単に論理を挿入することになる.ほとんどのコーディネートコードには似たような機能があり、標準的なツールメソッドに入れることができ、より使いやすいです.
最初の標準修飾器はフィルタです.実装時に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