プログラミング初心者がアーキテクトっぽく語る

見苦しい記事も多数あるとは思いますが訂正しつつブログと共に成長していければと思います

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の使い所についてはあまり厳密な設計プラクティスはないようだ。