Webアプリ開発をしているとよく、画面プレゼンテーション層と
サービスロジック層の間の為にコンバータなるものを作らされたりして
面倒なものです。
よく書かされてしまう、getter で持ってきて、setter に食わせる
a.setPhonNumber(b.getPhoneNumber());
みたいなものを大量に書かされて、まあコンパクトに書けないことはないんですけど、
単純に左から右へ渡すのでなく、加工などの処置が必要で
生成済インスタンスの状態毎に処置が必要な時は、面倒くさいものです。
先日の、new 演算子で生成する変数のコーディングを減らす方法 - Oboe吹きプログラマの黙示録
に触発されて、
名称はさておき、以下を考えました。。。
getterとして、Function<T, R> で取得して、setter として BiConsumer を実行します。
import java.util.function.BiConsumer; import java.util.function.Function; @FunctionalInterface public interface ApplyBiConsumer<T, U>{ void accept(T t, U u); static <T, U, V> ApplyBiConsumer<T, U> of(Function<T, V> f, BiConsumer<U, V> c) { return (t,u)->{ c.accept(u, f.apply(t)); }; } }
使用サンプルは以下のとおりです。
import lombok.Data; @Data public class Foo{ private String name; private int id; private LocalDate birthday; } import lombok.Data; @Data public class Person{ private String name; private int id; private LocalDate birthday; private String info; }
Foo foo; // Foo のインスタンス Person person; // Person のインスタンス // TODO foo と person のインスタンス生成、 // foo から person へ情報をセット ApplyBiConsumer.of(Foo::getName, Person::setName).accept(foo, person); ApplyBiConsumer.of(Foo::getId, Person::setId).accept(foo, person); ApplyBiConsumer.of(Foo::getBirthday, Person::setBirthday).accept(foo, person); // 型が違うものをセットする例 ApplyBiConsumer.of(e->((Foo)e).getDay().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")) , Item::setInfo).accept(foo, person); // もしくは、BiConsumer の方で対処する場合、、 ApplyBiConsumer.of(Foo::getDay, (t, u)->{ ((Person)t).setInfo(((LocalDate)u).format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"))); }).accept(foo, person);
a.setPhonNumber(b.getPhoneNumber()); の記述形式の方が短いと言えますが、
ラムダ式で書けるということは、変換式をsetter である BiConsumer の実行まで待てるので、
以下のように、この ApplyBiConsumer をリストに溜めてから実行できます。
List<ApplyBiConsumer<Foo, Person>> alist = Arrays.asList( ApplyBiConsumer.of(Foo::getName, Person::setName), ApplyBiConsumer.of(Foo::getId, Person::setId), ApplyBiConsumer.of(Foo::getBirthday, Person::setBirthday) );
を用意しておけば、(Java11なら、List.of() で書くと思います。)
alist.stream().forEach(e->e.accept(foo, person));
のように、いつでもセットを実行できるわけです。
でも、この ApplyBiConsumer は、以下のように、BiConsumer を継承したものとして、
定義した方が良いのかもしれません。
継承なら、 void accept(T t, U u); を以下のとおりここでは書かないです。
import java.util.function.BiConsumer; import java.util.function.Function; @FunctionalInterface public interface ApplyBiConsumer<T, U> extends BiConsumer<T, U>{ static <T, U, V> ApplyBiConsumer<T, U> of(Function<T, V> f, BiConsumer<U, V> b) { return (t,u)->{ b.accept(u, f.apply(t)); }; } }
最終的には、後日投稿の以下がベスト
Functionの結果をBiConsumerで実行する(3) - Oboe吹きプログラマの黙示録