JavaBeans 規約に従いつつカプセル化もしたいのですが

Java といえば JavaBeans 規約、すなわち getter/setter のウザさで有名ですが、古くは S2JDBC*1、近頃は JPA でも public フィールドが使えるようになったりして public なフィールドへの障壁が下がってきたのではないかと思います。とはいえまだまだ JavaBeans 規約に則っていることを前提にしたライブラリやフレームワークが数多くあります。例えば最近では JSF の EL 式から public フィールドを参照できなくて悲しい思いをしました。

そこで lombok ですよ

lombok というライブラリがあります。

アノテーションを付与することで getter/setter や equalshashCode といっためんどくさいコードをコンパイル時に自動生成してくれるというすぐれものです。この間 JavaでIDEのアクセッサ生成よりlombokを使ったほうがいい理由 - きしだのはてな で紹介されていたのを読んで NetBeans で普通に使えることを知りました。

これで getter/setter のメンテナンスからも解放され、 public フィールドなんて使わなくても JavaBeans 規約に則った方式でフィールドにアクセスできるようになります。プロパティ構文の代替になりますね。昨日、今日とちょこちょこ試験的に使ってみていますが、とても便利です*2。これで C# に追いついたで!

とはいえそもそも直接フィールドにアクセスできていいの?

何も考えず public な getter/setter を作るというのは public なフィールドと同様、直接フィールドにアクセスしているのと同じですね。カプセル化もくそもあったもんじゃありません。 DTO のような、カプセル化とか別にどうでもいいようなクラスならともかく、ロジックを集約すべきドメインオブジェクトなんかで内部情報だだもれでいいのかと。

以前システム設計の増田さんの講演をお聴きする機会があったんですが、そこで「アクセッサはドメインオブジェクトのロジックではない。だからアクセッサは禁止している。*3」というようなことを話されていました。ここで前述の通り「ライブラリ・フレームワークの都合上 getter/setter が必要になる場合があるはずだけどどうするんだろう」と疑問に思ったのですが、なんと getter/setter に deprecated を付けることで、ライブラリ・フレームワークに対応しつつプロダクトコードからの使用を事実上禁止しているということでした。これはなるほど!と思ったものです。

deprecated なアクセッサを lombok

とはいえ getter/setter 作った上いちいち deprecated 指定していくのはめんどくさすぎるので、 lombok でできないかなーと調べてみると一応できることはできるようです。以下の様な感じです。

    @Getter(onMethod = @_(@Deprecated))
    private String foo;

これで deprecated な getter が生成されます。なんか見慣れない @_ とかあったりして実にあやしげですね*4。しかし onX に書かれているように、これは実験的な実装のようです。利用する場合は相応の覚悟が必要です。

まとめ

というわけで個人的にはプロパティ構文的なものが使えれば便利だなーとは思うものの、結局カプセル化を安易に壊すことになりかねないので、「プロダクトコード以外からのみ使える public なアクセッサ」というのを定義できればいいのかなーと思いました。ハック臭がひどい感じですが・・・。

*1:使ったことないけど

*2:とはいえ軽く黒魔術的なアレなので、ハマるとひどいことになるという話もあったり?

*3:オレオレ意訳

*4:よくわかってない