velocityのいけていないところ - getter,setterはもういらない? 2015/01/03

javaです。Velocityです。
十分に枯れた感じで、安心して使えるVelocityですが、いけていないところがあるなーと数年前から思ってた点があります。

 テンプレートエンジンに、POJO(ここでは、getter,setterをもつjavaオブジェクトの意として使ってます)を渡すのですが、テンプレートエンジンからは、フィールド変数に直に値をとるのではなく、getterを経由でアクセスするという制限があることです。

例えば、$aaa.bbb と記述した場合、内部では、$aaa.getBbb()と解釈してアクセスします。まったく問題ありません。では、これを何故、僕は、制限としてとらえるのか。

教科書的(どこにそんな教科書があるんだ?)に考えると、きっと、内部の値に直接、触らせないのが、オブジェクト指向(思考、嗜好)的にはいいということになるのかなと考えてます。まあ、そのためのアクセス修飾子だったりするわけですが、いつの頃から、getter,setterはお作法になり、ボイラーテンプレートとなってるわけですが、これが、面倒極まりない。

プログラミング言語によっては、変数は宣言し、値を入れると、不可変を保証するようなものもある時代に、値を保持(hold)する ためだけのオブジェクトに、getter,setterを用意するこのつらさ。。。

いや、もしかして、それを回避するというか、制限としてではなく、使える方法があるのかもしれませんが、いまのところみつけきれていません。

 調べるとVelocityには、org.apache.velocity.app.FieldMethodizerというユーテリティクラスがあるのですが、これをかますと、publicでstaticなフィールド変数(field)にアクセスできます。ですが、これは、あくまでもstaticなフィールド変数(field)のみ。

設計思想や、ポリシーがあってこうしたとは思うのですが(メーリングリストを漁ればでてくる?)、publicなフィールド変数に直にアクセスできる方法を用意してもらいたかったというのが正直な気持ちです。

 というわけで、すでにあるFieldMethodizerをベースに作成してみました。
ちなみに既存のFieldMethodizerを拡張(extend)して作る方法はあきらめました。
継承して作るには、privateでがちがちに作られてるので、これまた改造しずらい。

以下コード、名前は、PublicFieldMethodizerとしてみました。

import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.HashMap; public class PublicFieldMethodizer { /** Hold the field objects by field name */ protected HashMap fieldHash = new HashMap(); protected Object target; /** * Constructor that takes as it's arg a living object to methodize. Note * that it will still only methodized the public static fields of the class. * * @param o * Name of class to methodize. */ public PublicFieldMethodizer(Object o) { try { addObject(o); } catch (Exception e) { System.err.println("Could not add " + o + " for field methodizing: " + e.getMessage()); } } /** * Add an Object to methodize * * @param o * @throws Exception */ public void addObject(Object o) throws Exception { this.target = o; inspect(o.getClass()); } /** * Accessor method to get the fields by name. * * @param fieldName * Name of static field to retrieve * * @return The value of the given field. */ public Object get(String fieldName) { Object value = null; try { Field f = (Field) fieldHash.get(fieldName); if (f != null) { value = f.get(this.target); } } catch (IllegalAccessException e) { System.err.println("IllegalAccessException while trying to access " + fieldName + ": " + e.getMessage()); } return value; } /** * Method that retrieves all public static fields in the class we are * methodizing. */ private void inspect(Class clas) { Field[] fields = clas.getFields(); for (int i = 0; i < fields.length; i++) { /* * only if public */ int mod = fields[i].getModifiers(); if (Modifier.isPublic(mod)) { // fieldHash.put(fields[i].getName(), fields[i]); } } } }






: