Effective Javaを読むチャレンジ-項目19~20-

項目19 型を定義するためだけにインタフェースを使用する

インタフェースは型の定義として使用するのが適切だ、という話です。

ここでいう型、というのはインスタンスの参照に使用できる型です。List list = new ArrayList・・・のListインタフェースのような使い方ですね(総称型は略)。つまり型の定義として使用するということは、「インタフェースをクラスが実装する」ということと同じです。

言い換えると、クラスが実装する目的として使用されないインタフェースは不適切だということになります。その例として挙げられているのが定数インタフェースです。

定数インタフェースは、メソッドを持たず定数だけを定義したインタフェースのことです。クラスはこのインタフェースの定数を利用するためにimplementsを使って実装しないといけません。これの何がいけないのかということを箇条書きにするとこんな感じです。

  • 定数は実装の詳細であり、それを公開APIに漏えいさせてしまう
  • クラスのユーザにとってそのクラスが定数インタフェースを実装していることに意味はない
  • 将来そのインタフェースが無用になったとしても、互換性のために削除できない
  • サブクラスのすべてがそのインタフェース内の定数によって名前空間を汚される

ボロクソですね。定数インタフェースの代わりに、定数を外部へ公開するには、その定数が強く結びついているクラスやインタフェースに定義する、enum型で定義する、またはユーティリティクラスに定義して提供する、などがいいようです。

定数インタフェースはダメ(本書では下手な使い方と言ってます。こっちの言い方の方が技術者にとっては辛いでしょう)ですが、個人的には定数クラスもあまり好きじゃないですねえ・・・Constantsクラスとかいう名前で共通定数クラスなどと呼んで、BLANK=””とか、ONE=1とか、なんかそういうの詰め込んでる現場もありました。

BLANKだとスペース含むのでせめてEMPTYにすべきだし、ONEなんて定数、1とする意図が結局分からないままなのでマジックナンバーの解決にならず、本末転倒の実装としか思えません。後になって仕様が変わって1を0としないといけなくなった場合、定数の定義値でなく、使用する定数を変更して、必要な箇所のONEをZEROに変えていく作業をすることになります(ONE=0という定数を使い続けることを我慢できるならいいですが)。

定数クラスがダメだというより、あまり上手い使い方をしてないことが多いので好きじゃないという感じです。

項目20 タグ付クラスよりクラス階層を選ぶ

タグというのは特性です。複数の特性を持つインスタンスが、その特性を示すためのタグフィールドを持っているというクラスです。

タグ付クラスの何がよくないかというと、複数の特性ごとの実装が1つのクラスにごっちゃに混ざるからです。そのため、enumやswitch文などで実装が複雑になって可読性も下がり、インスタンスのコストも膨れ上がるということです。さらにそのインスタンスのデータ型が、特性の手がかりを提供しないということにもなります。

その改善策として、タグ付クラスをサブタイプ化することを挙げています。サブタイプ化というのは、抽象クラスをクラス階層の上位に作成し、特性ごとに分岐していた処理を抽象メソッドとします。そして各特性ごとのサブクラスを作り、分岐していた処理をそれぞれの特性に応じて実装していく方法です。

これはリファクタリングの話ですね。このあたりは特に難しい言い回しもなく、すんなり読めました。

広告
  • LINEで送る