【Ruby】クラスメソッドの書き方と使い方の基本
開発環境
- Ruby version: ruby 3.1.2
Rubyのクラスメソッドとは
Rubyのクラスメソッドとは、クラスの特異メソッドのことです。 クラス自体に関連付けられたメソッドで、そのクラスのインスタンスではなく、クラスそのものに対して呼び出されます。 クラスメソッドは通常、クラスに関連するユーティリティ関数やファクトリメソッドを実装するために使用されます。 公式リファレンス:https://docs.ruby-lang.org/ja/latest/doc/spec=2fdef.html#class_method
Rubyのクラスメソッドの使いどころ
Rubyのクラスメソッドは基本的にクラス全体に関連する機能や操作を提供するためのものです。 クラスメソッドの一般的な使いどころとしては、オブジェクトのインスタンスを生成するための「ファクトリメソッドを定義」、「ユーティリティ関数の提供」や「カウンターの管理」など様々です。
Rubyのクラスメソッドの使い分け
Rubyのクラスメソッドの使い分けについては開発方針によっても異なります。 基本的には、クラスメソッドはクラス全体に関連する操作やデータ、ユーティリティを提供するために使われ、インスタンスメソッドはオブジェクト固有の振る舞いや相互作用を定義するために使われます。 そのため、クラスメソッドはクラス全体の情報を読み書きする場合に、インスタンスメソッドは個別に作成されたインスタンスの情報を読み書きする場合に使われる仕組みとして使い分けるのがおすすめです。
Rubyのクラスメソッドの書き方
Rubyのクラスメソッドの書き方をご紹介します。
メソッド定義の前に「self.」を付ける
メソッド定義の前に「self.」を付ける書き方です。
1# クラスの定義 2class SampelClass 3 # クラスメソッドの定義 4 def self.sample_class_method 5 puts "クラスメソッドを実行します。" 6 end 7end 8 9# クラスメソッドの呼び出し 10SampelClass.sample_class_method 11 12# =>クラスメソッドを実行します。
上記の例では、「sample_class_method」は「SampelClass」のクラスメソッドです。 クラスメソッドは、クラス自体に関連付けられているため、インスタンスを作成する必要はありません。
クラス定義内に「class << self ブロック」を使用する
クラス定義内に「class << self ブロック」を使用する書き方です。
1# クラスの定義 2class SampelClass 3 class << self 4 # クラスメソッドの定義 5 def sample_class_method 6 puts "クラスメソッドを実行します。" 7 end 8 end 9end 10 11# クラスメソッドの呼び出し 12SampelClass.sample_class_method 13 14# =>クラスメソッドを実行します。
ネストは一つ深くなりますが、「class << self」内でクラスメソッドを定義することにより、ブロック内のメソッドはクラスメソッドとして定義することができます。
Rubyのクラスメソッドの使い方
Rubyのクラスメソッドのよくあるパターンをサンプルコードを用いて使い方の解説をしていきます。
Rubyのクラスメソッドをクラスオブジェクトから実行するパターン
Rubyのクラスメソッドをクラスオブジェクトから実行するパターンです。
1# メソッドの定義 2class Exam 3 # 合計の合格ライン 4 def self.passing_total 5 400 6 end 7end 8 9# クラスメソッドの実行 10passing_total = Exam.passing_total 11 12# インスタンスメソッドの実行結果を出力 13puts(passing_total) 14 15# => 400
「Exam」クラスを定義してテストの合格点をクラスメソッドで定義をしています。 サンプルコードでは「Exam」クラスにドット(.)で「passing_total」を記述してクラスメソッドを呼び出し、合計の合格ラインを出力しています。
Rubyのクラスメソッドをインスタンスメソッドから実行するパターン
Rubyのクラスメソッドをインスタンスメソッドから実行するパターンです。
1# メソッドの定義 2class Exam 3 # インスタンスの初期化 4 def initialize(scores) 5 @scores = scores 6 end 7 # 合計点数 8 def total_score 9 @scores.sum 10 end 11 # 合格点を超えているかの判定 12 def passed_total? 13 if total_score >= self.class.passing_total 14 "合格" 15 else 16 "不合格" 17 end 18 end 19 # 合計の合格ライン 20 def self.passing_total 21 400 22 end 23end 24 25# メソッドの実行 26exam = Exam.new([70,90,70,80,90]) 27result = exam.passed_total? 28 29# インスタンスメソッドの実行結果を出力 30puts(result) 31 32# => 合格
「Exam」クラス内に合計点数と合格ラインを超えているかのインスタンスメソッドを定義しています。 定義したインスタンスメソッド「passed_total?」から、「self.class」にドット(.)でクラスメソッド名の「passing_total」を記述することにより、インスタンスメソッド内でクラスメソッドを呼び出しています。
Rubyのクラスメソッドでローカル変数を参照するパターン
Rubyのクラスメソッドでローカル変数を参照するパターンです。
1# メソッドの定義 2class Exam 3 # インスタンスの初期化 4 def initialize(scores) 5 @scores = scores 6 end 7 # 合計点数 8 def total_score 9 @scores.sum 10 end 11 # 合格点を超えているかの判定 12 def passed_total? 13 if total_score >= self.class.passing_total 14 "合格" 15 else 16 "不合格" 17 end 18 end 19 # 合計の合格ライン 20 def self.passing_total 21 400 22 end 23 # 合計の合格ラインを変更することができるようにする 24 def self.set_passing_total(score) 25 define_singleton_method(:passing_total) do 26 score 27 end 28 end 29end 30 31# メソッドの実行 32Exam.set_passing_total(450) 33exam = Exam.new([70,90,70,80,90]) 34result = exam.passed_total? 35 36# インスタンスメソッドの実行結果を出力 37puts(result) 38 39# => 不合格
「define_singleton_method」を使うことで、定義時のローカル変数を特異メソッドから参照することができます。 Rubyのブロックはクロージャなので、define_singleton_method に渡したブロック内では、定義時のスコープが引き継がれており、「score」を参照できます。
おわりに
Rubyのクラスメソッドの使い方を解説してきました。 クラスメソッドとインスタンスメソッドの違いがわかれば、クラスメソッドとインスタンスメソッドの使い分けもしやすくなります。 最初は難しいかもしれませんが、しっかりと静的なクラスメソッド、動的なインスタンスメソッドを使いこなしていきましょう。 ド