ユーティリティクラスとは、さまざまなクラスの処理の中で頻出する共通処理をまとめたクラスのことです。普段皆さんが扱っているリポジトリの中で「Common.java」や「○○Utils.java」という名前で作成されているクラスがあるとしたら、おそらくそれのことです。クラスの中には、いくつかのprivate static finalなメンバといくつかのstaticメソッドがあるかと思います。
public class Common {
public static final String ○○ = ...
public static String △△ = ...
}
1. クラスをfinalにする
ユーティリティクラスのメンバやメソッドは基本的にpublicで宣言されてstaticに呼ばれることを想定していますが、書き手によってはユーティリティクラスを自分が作成するクラスに継承して利用しようとします。
public class ChildClass extends Common {
...
}
しかし、is-aの関係を満たさないこのような継承は混乱のもとであり、クラスの結合度を無駄に高めてしまい、修正・変更の障壁です。
そのため、クラスにfinal修飾子を付与して継承を不可能にします。(finalを外す修正をしたコーダーがいた場合はレビューでブロックします)
public final class Common {
...
}
public class ChildClass extends Common { // コンパイルエラー
...
}
2. コンストラクタを隠蔽(いんぺい)する
ユーティリティクラスのメンバとメソッドはstatic参照されるため、インスタンスを作成する必要はありませんし、するべきではありません。なので、デフォルトコンストラクタを明示的にprivateにして、インスタンス化を防止します。
public final class Common {
private Common() {}
}
しかし、これではReflectionで参照されてしまうため、コールされた際にErrorをスローして確実に実行させないようにします。
public final class Common {
private Common() {
new AssertionError();
}
}
最後に
自身が作ったクラスの誤用を防ぐこともAuthorの責任です。クラスを読む人と使う人のことも考えてコーディングして、サービスの保守効率を高めていきたいですね。