入れ子構造のクラス、例えば以下のようなクラス、
(setterやgetterなどはここでは省略)
public class Aunit{ private int id; private String name; private Bunit bunit; }
public class Bunit{ private String name; private Cunit cunit; }
public class Cunit{ public int id ; public String name; }
書いているロジック内、先頭のクラスのインスタンスだけ持っていって、
一番下の階層のクラスインスタンスを抽出するのは、getterメソッドのチェインを書かなくてはならないか、
いちいち1つ1つ宣言とgetter による取得を書かなくてはならない。
フィールド数が多いと見るのも厭になるし、3階層、4階層とネストが深くなる設計をされると、
非難の的であろう。
タイプセーフではないし、配列、リスト、マップでは使えないが、
以下のような簡単なユーティリティを用意する。
( org.yipuran.util.Fieldgetter :
yipuran-core/Fieldgetter.java at master · yipuran/yipuran-core · GitHub
を使ってる。)
import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; import org.yipuran.util.Fieldgetter; /** * GenericGetter */ public class GenericGetter{ private List<String> nlist; private GenericGetter() { nlist = new ArrayList<>(); } public static GenericGetter of() { return new GenericGetter(); } public GenericGetter with(Supplier<String> s) { nlist.add(s.get()); return this; } public GenericGetter with(String s) { nlist.add(s); return this; } @SuppressWarnings("unchecked") public <T, R> R get(T t) { Object o = t; for(String s:nlist) { o = Fieldgetter.of(e->s).apply(o); } return (R)o; } }
ちょっと大胆な名前だけど、サンプルなので、ご勘弁。
Aunit a = new Aunit(); // Aunit 内をセットした後で、、、 int id = GenericGetter.of() .with(()->"bunit") .with(()->"cunit") .with(()->"id") .get(a); String cname = GenericGetter.of() .with("bunit") .with("cunit") .with("name") .get(a);
with 順番で指定しなければならないが、パスとして確実な指定はできる。
今回は、フィールドの宣言名称を参照していく方法で、プロジェクトのコーディング規則、命名規則の
影響を受けやすい。
つぎは、フィールドの宣言名でなく、クラス定義、型で参照する方法を考える。。