はじめに
ある製品のJavaコードを読んでいてメソッドのアクセス修飾子の使い方が気になった。
「修飾子の選択には設計者の明確な意図があるに違いない」
そう思って色々と調べてみた。
アクセス修飾子の仕様
| アクセス修飾子 | 説明 |
|---|---|
| public | すべてのクラスからアクセスできる |
| protected | 同一パッケージのすべてのクラスとサブクラスからアクセスできる |
| package private | 同じパッケージのクラスからアクセスできる |
| private | 同じクラス内からだけアクセスできる |
public
世界中のみんなに使ってもらうメソッドにつける
シグネチャはクラスが提供する機能を端的に表す
private
クラス外部に公開する要件がないのであれば基本はprivateにする
public/protected/package privateメソッドから抽出された処理の一部を切り出してメソッド化した場合などにつける
package private
Effective Javaを読むとpackage privateは「クラスの実装の一部」とのこと。 クラス外部でも使うが、パッケージの外(=世界中)に公開する必要がないものにつける。 「チームの皆で使うメソッド」ということになる。
しかし製品のコードを読んでいると全く理解できない使い方が散見される。 自分のクラスでしか利用しておらず、実質privateなのにpackage privateにしているケースがあった。 なぜだろう?
protected
Effective Javaを読むとprotectedは「クラスが公開するAPIの一部」とある。 つまり「publicよりは狭い範囲だけど世界中のみんなに使ってもらうメソッド」ということになる。 特に「継承」という形で使ってもらうことに焦点が置かれている。
故にデザインパターンなどの本を読んでいると、パッケージ内外を問わずサブクラスになにか期待していることを示すマーカーのような意味合いで使われている。
- サブクラスで固有の処理を実装(オーバーライド)することを期待している
- テンプレートメソッドのような場合
- サブクラスが呼び出すことを期待している
- 言語仕様では同じパッケージの全クラスがアクセス可能だが、サブクラス以外からの呼び出しは想定していない場合
ところが製品のコードを読んでいると全く理解できない使い方が散見される。
- privateでもいいケースで使っている
- スーパークラスもサブクラスもいない具象クラス(=package privateでもいいケース)で使っている
疑問
教科書的な付与基準は理解できた。
しかし実際のコードを読んでいるとprotected、package private、privateとの棲み分けが理解できない。
プロに聞いた
たまたま通りかかったプロに聞いてみた(読んでいたコードの開発者ではない)。
- 将来の拡張性を考えてprivateやpackage privateでもよいメソッドをprotectedにすることはある。
- 拡張性も考慮した上で必要最小限の可視性を与えるだけだが、その判断は属人的で感覚的になりやすい。
- 拡張性を考慮した結果だった場合、現在のコードだけ見てもprotectedやpackage privateにした根拠を見つけるのは難しい。
- コードリーディングする上ではpublicか否かに注目すれば大丈夫。
結論
自分が修飾子を付与する際は拡張性も考慮した上で必要最小限の可視性を与えればよい。
しかし他人のコードを読むときは修飾子のみで書き手の意図を明確に読み取れないことがあることにも留意する。