Javaのメソッドのアクセス修飾子の使い分け
注
本稿は筆者の雑感です。思いついたことを書いてます。いずれちゃんと調査、考察を行ってちゃんとした記事にしたいと思います。
はじめに
ある製品のJavaコードを読んでいてメソッドのアクセス修飾子の使い方が気にった。「修飾子の選択には設計者の明確な意図があるに違いない」と思って色々と考えたり、調べたりしたことをここに記す。
アクセス修飾子の仕様
アクセス修飾子 | 説明 |
---|---|
public | すべてのクラスからアクセスできる |
protected | 同一パッケージのすべてのクラスとサブクラスからアクセスできる |
package private | 同じパッケージのクラスからアクセスできる |
private | 同じクラス内からだけアクセスできる |
public
みんなに使ってもらうメソッドにつける
シグネチャはクラスが提供する機能を端的に表す
private
クラス外部に公開する要件がないのであれば基本はprivateにする
public/protected/package privateメソッドから抽出された処理の一部を切り出してメソッド化した場合などにつける
protected
ここはよくわからない。
Effective Javaを読むとprotectedは「クラスが公開するAPIの一部」とある。つまり「publicよりは狭いけどみんなに使ってもらうメソッド」ということになるはず。
また、デザインパターンなどの本を読んでいると、サブクラスになにか期待していることを示すマーカーのような意味合いがあるようにも見える。
- サブクラスで固有の処理を実装(オーバーライド)することを期待している
- テンプレートメソッドのような場合
- サブクラスが呼び出すことを期待している
- 言語仕様では同じパッケージの全クラスがアクセス可能だが、サブクラス以外からの呼び出しは想定していない場合
ここまでは理解できる。ところが製品のコードを読んでいると全く理解できない使い方が散見される。
- privateでもいいケースで使っている
- スーパークラスもサブクラスもいない具象クラス(=package privateでもいいケース)で使っている
package privateやprivateとの棲み分けが理解できない。
package private
ここもよくわからない。
Effective Javaを読むとpackage privateは「クラスの実装の一部」とのこと。つまり「みんなに使ってもらうメソッド」ではなく「俺が同一パッケージ内で自由に使うメソッド」ということになる(ここで言う「俺」には極めて近い立場で仕事をしている同僚も含んでいる)。要は「パッケージの公開APIを実現する裏方としてパッケージの実装者が勝手に作成、変更、削除してもよいメソッド」ということなのだと思う。
しかしここでも製品のコードを読んでいると全く理解できない使い方が散見される。自分のクラスでしか利用しておらず、実質privateなのにpackage privateにしているのだ。
プロに聞いた
たまたま通りかかったプロに聞いてみた(読んでいたコードの開発者ではない)。
- 将来の拡張性を考えてprivateやpackage privateでもよいメソッドをprotectedにすることはある。
- 拡張性も考慮した上で必要最小限の可視性を与えるだけだが、その判断は属人的で感覚的になりやすい。
- 拡張性を考慮した結果だった場合、現在のコードだけ見てもprotectedやpackage privateにした根拠を見つけるのは難しい。
- コードリーディングする上ではpublicか否かに注目すれば大丈夫。
packge privateとprotectedの使い所についてはあまり厳密な設計プラクティスはないようだ。