Effective Javaを読むチャレンジ-項目13~14-

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

いわゆるJavaのカプセル化の話ですね。実装とAPIを分離する、つまりモジュール間はAPIを通してやり取りするが、その実装の内容を他モジュールに知らせないようにすることです。

Javaにはそのための機能がいくつかあり、その一つがアクセス修飾子だということです。アクセス修飾子とは、クラスやメンバー(フィールド)、コンストラクタやメソッドなどが、自身を基準にした他モジュールからのアクセス可能性を示すための記述で、public、パッケージプライベート(アクセス修飾子を付けない)、protected、privateの4パターンあります。

このあたりはJavaの基礎ですのでそれぞれの解説はいいとして。本書ではそのカプセル化(本書では情報隠ぺいと呼んでいます)が重要な理由を長い段落で説明しているのですが、いろいろ背景を端折ってぱぱっと理由だけ並べているので、読んでいてカプセル化が重要だという理由が理解できません。

情報隠ぺいはシステム開発のスピードを向上させる

実装とAPIを分離した場合、システム開発でのメリットは、APIの呼び出し側モジュールの開発を担当している部署が、APIの実装を担当している部署の、実装の完成を待たずに開発を進められるという点です。

このとき、APIの呼び出し側は、呼び出すAPIのモックを作ってそのAPIが設計通り呼び出された体で自分たちの機能をテストします。実装側はその間に実装を進めます。まあそのせいで、その後の結合テストでいろいろ問題が起こることもしばしばですが、それはまた別の話。

モジュールをすばやく理解できる

APIと実装が分離されていないと、APIの利用者は複雑な実装内部まで理解しようとするかもしれません。実装が分離されていれば、APIの利用者は呼び出すAPIのシグネチャや例外や、その戻り値など最低限の情報を理解すればいいだけとなります。

他のモジュールに対して害を及ぼすことを心配することなくデバッグできる

APIと実装が分離されていれば、デバッグする際に実装部分だけデバッグすればいいので保守のリスクが減りますね、ということです。

情報隠ぺいは、効果的なパフォーマンス・チューニングを可能にする

これは、パフォーマンスの悪い実装が見つかった場合に他のモジュールに影響することなく、その悪い実装部分だけをチューニングして交換することができるということです。

情報隠ぺいはソフトウェアの再利用を促進する

もしそのシステム開発が失敗したとしても、有用なモジュールだけを取り出して再利用できるということですね。

ここまでの話はソフトウェア開発におけるモジュールの結合度というヤツです。この後、本書ではアクセス可能性と、そのアクセス可能性を最小限にするための説明をしています。そのあたりをざっくりまとめます。

アクセス可能性を最小限にするために

  • publicなクラスは公開APIのクラスのみにして、あとはパッケージプライベートなクラス(パッケージの実装の一部)にする
  • 1つのクラスからしか使われないパッケージプライベートなクラスは、そのクラスのネストしたprivateなクラスにすることを検討する。ただし、優先度は低い
  • オーバーライドされたメソッドのアクセス可能性は広げることはできるが狭めることはできない
  • 基本的にメンバはすべてprivateにするべきだが、パッケージプライベートとするべきこともある
  • インスタンスフィールドは決してpublicにすべきではない
  • public static finalのフィールドは、基本データ型か不変オブジェクトであることが不可欠
  • public static finalが配列だったり、そのフィールドへのアクセサを持ったりしてはいけない

Javaの配列は長さが0でない場合、必ず可変になります。ですので、最後の項目はfinalをつけただけでは、配列内部の変更を防ぐことができないからダメだよということです。finalな配列を変更できるアクセサなんかもっているなんてのは言語道断ですね。配列内部の変更を防ぐには、以下のようにします。

Collections.unmodifiableListメソッドは、指定されたリストの変更不可能なビューを返します。つまり読み取り専用のリストを作ってくれるということです。もし、どうしても配列でないとダメだという場合は、次の方法があります。

このようにprivateな配列をコピーするメソッドを公開すればいいということです。参照が別になるので元の配列が変更されることはなくなります。

Javaのカプセル化についての説明でちょっと詰まりましたが、テクニック的な部分は読みやすかったです。

項目14 publicのクラスでは、publicクラスのフィールドではなく、アクセッサーメソッドを使う

変更可能なpublicなクラスのフィールドはprivateにして、publicなgetter/setterメソッドでアクセスさせるべきという話です。それだけの短い項目ですが、重要ですね。

ただし、それはあくまでpublicなクラスの話であって、パッケージプライベートなクラスや、privateなネストされたクラスのフィールドについてはgetter/setterを用意する必要はなく、直接公開した方が使いやすい場合もあるよ、ということも書かれています。私は昔、パッケージプライベートなクラスでも盲目的にgetter/setter使っていた気がします・・・反省ですね。

広告
  • LINEで送る