【Effective Java】項目13:クラスとメンバーへのアクセス可能性を最小限にする

ここから第4章「クラスとインターフェス」。

クラスとインタフェースは Java の中心に位置し、抽象化の基本となる要素。 この章では、クラス・インタフェースが利用可能で、頑強で、柔軟になるような指針を議論する。

最初の項目は情報隠蔽カプセル化に関する項目。

情報隠蔽カプセル化

上手く設計されたモジュールとそうでないモジュールを区別するには、内部データと実装を他のモジュールからどの程度隠蔽しているかどうか重要(らしい)。 この概念は、情報隠蔽カプセル化と呼ばれおり、ソフトウェアの基本的な教義のひとつ。

情報隠蔽を適切に行うといろいろ利点がある。 が、よく話される話題なので本ブログでは割愛する。

Java情報隠蔽を行うための機能のひとつが、クラス、インターフェス、メンバーのアクセス制御の仕組み。

クラス・インタフェースの情報隠蔽

トップレベルのクラスやインタフェースに対してのアクセス制御は、パッケージプライベートと public の2種類である。 public 修飾子をつければ public、そうでなければパッケージプライベートである。

トップレベルのクラスやインタフェースを public にすると公開 API となり、永久にそれをサポートする義務を負う。 そのため、なるべくパッケージプライベートにするべきである。

なお、一つのクラスだけに利用されるクラス・インタフェースは private のネストしたクラス(項目22)にすることを検討するべき。

メンバーの情報隠蔽

メンバーには4つのアクセスレベルがある。

  • private:それが宣言されたトップレベルのクラス内でのみアクセス可能。
  • パッケージプライベート:それが宣言されたパッケージ内のどのクラスからでもアクセス可能。アクセス修飾子を何も付けない場合。
  • protected: それが宣言されたパッケージ内のどのクラスと、それが宣言されたクラスのサブクラスからアクセス可能。
  • public:メンバーはどこからでもアクセス可能。

メンバーの場合も、なるべく private かパッケージプライベートにするべきであり、protected、public にすると公開 API となるため永久にサポートの義務を負う。 protected は public よりはマシだが、そのクラスが拡張されると他のパッケージからも利用されてしまう。

サブクラスがスーパークラスメソッドをオーバーライドする場合、スーパークラスメソッドよりも低いアクセスレベルを持つことはできない。 スーパークラスインスタンスが利用可能な場所で、サブクラスのインスタンスも利用可能にするためである。

なお、インタフェースのメソッドはすべて暗黙に public のため、それを実装する場合はすべて public と宣言する必要がある。

フィールドは public にしない

インスタンスフィールドは決して public にするべきではない(項目14)。 クラスが持つべき生のフィールドの制御権を破棄することになる。

例えば、そのフィールドに保存できる値の不変式を強制することができなくなる。 他にも、フィールドが変更された場合の処理を行うことが不可能になり、結果としてクラスがスレッドセーフでなくなる。

static のフィールドも同様だが、定数に関しては public にすることが一般的に認められている。 そのようなフィールドは public static final 修飾子を持ち、単語間がアンダースコアで区切られ、大文字で構成される(項目56)。

感想

まぁよくある話だなーという感じ。private 万歳。

開発してる時は、アクセス制御が適切でなくてもなかなか問題が表面化しないんだけど、あとからメンテする人がほんとに苦労する。 過去にそういうプロジェクトに従事したことがあって発狂するかと思った(表現は盛ってるけど)。

そういえば、Java の final は参照先への変更は禁止できないよね。 C++ だと参照先への変更も禁止する const Obejct* const a; とかあるんだけど。

情報隠蔽を行うと「システム全体は失敗しても個々のモジュールが独立して成功するかもしれない」という言及は興味深かったな。 情報隠蔽オブジェクト指向の最大の特徴っていうのはどっかの教科書で目にした気がするが、覚えてないなぁ、、、