2016/09/01 このエントリーをはてなブックマークに追加 はてなブックマーク - 【Java】定数クラスをどうしたものかと改めて考える

【Java】定数クラスをどうしたものかと改めて考える


いや、大した話じゃないんですけど
みんなどうしてるのかなって思って。



Javaの定数クラス。皆さんの使用状況はこんな感じだろうか。

  • なにそれ?
  • 知ってるけど使ってない
  • 全部propertiesファイルとかxmlとかに持ってるから使わない
  • 使ってる


使うとすればどのように使うのが良いかなとか。
わざわざ考えたりしないような気がするので、あえて考える。





定数クラスとはpublic static finalなフィールドをたくさん持つクラスで、
定数を管理するために用いられる感じ。

ざっくりとこんなの。

見たことある人は「あー、、。。。」となる。

public final class Constants {
    public static final String SLASH = "/";
    public static final String BLANK = " ";
    public static final String CRLF = "¥r¥n";
    public static final String LF = "¥n";
    private Constants (){}
}

ざっと思いつくものを。

  • public finalなクラスであるべき
  • privateコンストラクタを持ちインスタンスは生成しない
  • フィールドはpublic static finalである

しょーじき、privateコンストラクタとかfinalなクラスとかじゃなくてもいいやんとも思える。これは性善説的な考え。

コンパイラの力を利用したいのであれば、こういうコテコテの手法を取ったほうが良いなとも思う。


これも、ざっと思いつくものを。



  • 定数の数が多い

とにかく定数が多い。どこに何があるのか追えない。
コード補完で探すのが一苦労。



  • 名前が分かりにくい

こんなんとか。

public static final String ONE = “1”;
public static final String TWO = “TWO”

この例見て悪い冗談だなぁ…ハハハ…と思った人は幸せものかも知れないですね(意味深)



  • 同じ意味の定数が至るところにある

HogeConstantsとFugaConstantsで同じ定数があるとか。
同じ定数で意味合いが違ったりとかするのでその場合は良いのだけど、
全く同じ定数なのに色んな所に散見されるというのはモデリングの仕方が良くないのかなと思う。
それとか定数クラス以外の普通のクラスのprivate static finalなんちゃらで同じ定数があったりとか。。。
保守性がさがってしまいがち。



  • interfaceで定数を管理する

幸か不幸か、僕は実際のプロジェクトではお目にかかったがない。

でも流行ったらしい。定数をinterfaceに定義してその定数を使う側はimplementsするんだって。
それインターフェースじゃないがな!みたいな気持ちになる。

J2SE 5以降、staticインポートが出来るようになったので、もはやこれをやるメリットも無いし、使い方として良くないしという完全なアンチパターン。
とかいう話は以前にcero_tさんもしていたらしい。

[Java]考えなしに肥大化する定数クラス。- 谷本 心 in せろ部屋

java.io.ObjectStreamConstantsなど、Javaの中でこのアンチパターンが使われているのは良くネタにされる話。

3.7. インターフェースで定数定義


Effective Javaでは定数クラスよりenumを使いましょうと言っています。たしか。

Effective Java にのっている エレガントな Enum の使い方メモ - Futurismo

そもそもが定数クラスというのはtypesafeなenumが導入される以前の工夫だったため当然といえば当然な流れのように思います。

enumはJavaの5から導入されました。
この話の時は大体さくらばさんのこれが引用されます。

Typesafe Enum - J2SE 5.0 虎の穴


考えてみると定数だけが浮かび上がっているドメインていうのは不思議であり、
かなり限られているように思います。

本当ならばドメインのうちの「何かの属性の値」が定数という形で抽出されてしまっており、
ドメインから離れて固まっている可能性もある。

したがってJavaBeansなり、
前述したenumなりで正しくモデリングがなされているべきです。
でないと、定数クラスはどんどん肥大化してしまうでしょう。


当たり前の話ですが、例えば、
Colorクラスとか
Htmlクラスとか。
そういったモデリングであればそれに対しての属性だというのが明確になる。

例えば、定数であってもHogeNumberクラスのONEとHogeBookクラスのONEでは属しているクラスによって意味合いが違います。


ここまで話が飛躍すると段々身も蓋もなくなってきますが、
RDBMSなり、キャッシュ、インメモリDBとか、外部ファイル(xml、yml、properties)とか
そういうものを上手く使えば、定数クラスの役目は減るだろうと思います。

あとはフレームワークがちゃんと働けば、とか。


「いやいや、それでも男は黙って定数クラス!」とか

「そうは言っても、もうすでに定数クラスが山ほどあるんじゃい!」
とかそういうこともあると思います。

そういう場合は、これまでつらつらと書いたとおり、
なるべく定数クラスをドメインごとに分割する努力が必要です。

それでも、どうしても定数が膨大になってくることがあるかもしれません。特に巨大なシステムであったり、レガシーになってしまっていればなおさら。

そういう時はクラスの中にクラスを作って定数をグルーピングするのもありかなと思います。これどうなんだろうな。

public final class Constants {
    private Constants() {
    }
    public static class Money {
        public static final String YEN = "円";
        public static final String DOLLER = "ドル";
    }
    public static class Character {
        public static final String SLASH = "/";
        public static final String BLANK = " ";
        public static final String CRLF = "¥r¥n";
        public static final String LF = "¥n";
    }
}

こうすれば、こういう風にアクセス出来る。

System.out.println(Constants.Money.YEN);

これをやると

  • 親子関係が明確になるので意味が理解しやすくなる
  • コード補完で探しやすくなる
  • クラスの中でグルーピングされるので、ぱっと見で分かりやすくなる

とか良いこと?があるかなぁという気がする。

でも、これはあくまで最終手段というか、モデリングとかきちんとやったうえでこういうのも必要な時があればというか、そんな気持ち。

あと、単純にAのBという関係だけで表現出来ない時もあるんじゃないかなぁと思うんですよねぇ。

でもここまで頑張って定数クラス作る意味ってあるんかな。。




とまぁ、ぼんやり考えていることを書いてみましたが、答えはないです。
いやいやありえないだろ、、、とか色んな人からなんかしら意見が貰えると幸い。




このブログ記事から派生した話題






0 件のコメント:

コメントを投稿