2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

privateメソッドの影響範囲と使い所を確認する

Last updated at Posted at 2024-11-25

はじめに

「他の場所から呼び出せないように、他のクラスの処理に影響を与えないようにするために使う?」
プライベートメソッドについて分かっているようで、完全に理解している自信がなかったので、どんな状況で使うのかをしっかり確認し、意図をもって実装できるようになりたいと思い、今回は調べることにしました。

privateメソッドの目的

定義されたクラス内部でのみ使用され、クラス外部やサブクラスからは直接呼び出せないメソッドのことで、他のメソッドをサポートする「補助的なメソッド」や、クラスの内部動作をカプセル化するために使います。

クラスの内部動作をカプセル化するというのは、クラスの実装詳細(内部ロジックや状態)を隠蔽し、外部から直接アクセスできないようにすることを指していて、これにより、外部から誤って操作されるリスクを減らします。

そして、保守性の向上にもなります。というのも、プライベートメソッドにすることで、「このメソッドはクラス内部でしか使用されない」という意図を明確に示せるので、コードレビューや後々の修正時に、意図しない変更が生じるリスクを低減できるからです。

privateメソッドの特徴

インスタンスから呼び出されても答えてくれません。

image.png

あくまで、プライベートメソッドが働く範囲はクラスの内部だけになっています。
クラスの中の人たちとだけ口を利いてくれます。
というかクラス内の人にしか知られていないイメージ

image.png

image.png

コードで確認してみる

サンプルでコードを書いてみました。

    class Hoge
      
      def use_private_methods
        hoge
        hogehoge
      end

      # ここから下はprivateメソッド
        private
        def hoge
          puts "hoge"
        end
        def hogehoge
          # privateメソッド内で他のprivateメソッドも呼び出せる
          hoge
        end
      end
      
      # クラス内でプライベートメソッドを呼び出し
      Hoge.new.use_private_methods
      #=> hoge
      #=> hoge
    
      # プライベートメソッドはクラス外からは直接よびだせない
      Hoge.new.hoge
      #=> private method `hoge' called for 
      #<Fuga:0x000002529aed37f0> (NoMethodError)   

定義の仕方

これからプライベートメソッドを定義したいというときにprivateと書いてあげれば大丈夫です。
privateメソッドはprivateと書いたところから1段インデントしてあげると、他のメソッドと差がついて見やすくなります。

privateメソッド呼び出しルール

  1. インスタンスから直接呼び出せない
  2. 同じクラスのメソッドからの呼び出しは可能
  3. サブクラスからは呼び出せない

サブクラスでプライベートメソッドを使用したい場合、private にしてしまうと継承先で使えないので、代わりに protected を使うのが適切です。

基本的にクラス内でしか使わないメソッドはprivateにしておくとよさそうです。(←雑かも?)

privateにしておかないと、そのクラスから生成したインスタンスが、外部から呼び出せるメソッドになってしまうため、もし万が一、そのメソッドを間違えて使ってしまうと、予期せぬ事態になることも考えられます。

では具体的にクラス内でしか使わないメソッドはどんなものがあるのでしょうか?

privateメソッドをよく使うタイミング

補助的な処理をprivateメソッドに切り出すことが一般的です。

  • リクエストハンドリング

入力処理の整形や検証処理は、クラスの外部から直接呼び出される必要がないためprivateにするのが一般的。

例えば、ストロングパラメータを定義した時は、コントローラ外部から呼び出す必要はないので、privateメソッドとして定義する。

      private
      # ストロングパラメータ
      def user_params
        params.require(:user).permit(:name, :email, :password, :password_confirmation)
      end
    end
  • コールバック
    一応、そもそもコールバックとは

コールバックとは、オブジェクトのライフサイクル期間における特定の瞬間に呼び出されるメソッドのことです。コールバックを利用することで、Active Recordオブジェクトが作成/保存/更新/削除/検証/データベースからの読み込み、などのイベント発生時に常に実行されるコードを書くことができます。

コールバックの例

    class ArticlesController < ApplicationController
      before_action :set_article, only: [:show, :edit, :update, :destroy]
      
    ## 省略
     
      private
    
      def set_article
        @article = Article.find(params[:id])
      end
    end

このset_articleもクラスの外部から参照される利用する必要がないので、privateメソッドにします。

  • 共通処理の抽出
    クラス内の複数メソッドで使用されるが、外部から直接呼び出す必要のない共通処理をprivateに定義してまとめる。
サンプルコード by GPT🙏
class Product
  TAX_RATE = 0.1

  def initialize(price)
    @price = price
  end

  # 税込価格を返す
  def price_with_tax
    apply_tax(@price)
  end

  # 割引後の税込価格を返す
  def discounted_price_with_tax(discount_rate)
    discounted_price = @price * (1 - discount_rate)
    apply_tax(discounted_price)
  end

  private

  # 共通処理として税込価格を計算
  def apply_tax(amount)
    (amount * (1 + TAX_RATE)).round(2)
  end
end

おわりに

設計時に「この処理は外部に公開する必要があるか?」と意識することで、クラスの責務を明確にすることが大事だなと思いました。

またなぜこのメソッドをプライベートにするのか?を考えながらリーディング、実装していきたいと思います!

内容に不備あれば、ご指摘くださると幸いです。
最後までご覧いただきありがとうございました!

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?