【Ruby】Lesson5-04|クラス変数とクラスメソッドを理解しよう

ながみえ

一つ前のページではアクセスメソッドについて学習しました。

今回は クラス変数クラスメソッド について見ていきましょう。

Lesson1:基礎文法編
Lesson2:制御構造編
Lesson3:メソッド編
Lesson4:コレクション編
Lesson5:オブジェクト指向編

 ・Lesson5-1:クラスの基本を理解しよう
 ・Lesson5-2:イニシャライザを理解しよう
 ・Lesson5-3:アクセスメソッドを理解しよう
 ・Lesson5-4:クラス変数とクラスメソッドを理解しよう ◁今回はココ
 ・Lesson5-5:privateメソッドを理解しよう
 ・Lesson5-6:正規表現を理解しよう
 ・Lesson5-7:クラスの継承を理解しよう
 ・Lesson5-8:オーバーライドを理解しよう
 ・Lesson5-9:モジュールを使ってみよう
 ・Lesson5-10:ミックスインを使ってみよう
 ・Lesson5-11:ファイル操作を理解しよう
 ・確認問題5-☆1:モンスター捕獲ゲームを作ろう
 ・確認問題5-☆2:モンスターとの戦闘ゲームを作ろう
 ・確認問題5-☆3:マルバツゲームを作ろう

<<前のページ

Rubyの記事一覧

次のページ>>

クラス変数とクラスメソッドの定義と使い方

Rubyでは「クラス変数」と「クラスメソッド」を使用することで、クラス全体で共有されるデータや機能を扱うことができます。

これにより異なるインスタンス間でも共通の情報を管理することが可能になります。

クラス変数とは?|ローカル変数やインスタンス変数との違い

クラス変数はクラス全体で共有される値を保存するための変数です。

そのクラスから生成された全てのインスタンスや、 子クラス(Lesson5-7で学習) からも共通してアクセス可能となります。

クラスの中で定義できる変数は、以下の3種類があります。

  • ローカル変数:通常の変数。そのスコープ(メソッドの中など)でしか使えない。
  • インスタンス変数:各インスタンスごとに個別で持つ値。インスタンスメソッドの中で使う。
  • クラス変数:クラス全体で共有される値。すべてのインスタンスや子クラスからアクセス可能

クラス変数は変数名の最初に@@を付けて定義します。

class クラス名
  var_1 = "ローカル変数1"   # 通常の変数。スコープ内だけで有効。外部からやクラス内メソッドからもアクセスできない
  @@var = "クラス変数"	   # 全てのインスタンスからアクセス可能
  def initialize(value)	   # イニシャライザ
    @var = value		   # インスタンス変数 。各インスタンスごとに値が保存される
    var_2 = "ローカル変数2" # ここに定義したローカル変数は、このイニシャライザ内だけで使用可能
  end
end

クラス変数の使用例を見てみましょう。

以下のコードは、クラス変数を使用して全インスタンスで共通するカウントを管理する例です。

class User
  @@user_count = 0		# クラス変数の定義

  def initialize(name)	# イニシャライザ
    @name = name		# インスタンス変数@nameに引数nameを代入
    @@user_count += 1	# クラス変数に1を加算
  end

  def user_count		# user_countメソッドの定義
    @@user_count		# このメソッドの戻り値として、クラス変数の値を返す
  end
end

# インスタンス生成
user1 = User.new("Alice")
user2 = User.new("Bob")

puts user1.user_count	# インスタンスが2回生成された(イニシャライザが2回呼び出された)後なので、出力は2

クラスはただの設計図であり、インスタンス生成で作られたオブジェクトこそが実体です。

このコードで作られた2つのオブジェクトはそれぞれ別の物ですが、クラス変数だけは共有しています。

イニシャライザ内の「@@user_count += 1」が2回実行されたので、最後の出力結果は2となります。

クラスメソッドとは?|定義と呼出し方法

クラスメソッドはクラス自身に紐づくメソッドで、インスタンスを作成しなくても呼び出すことができます。

  • インスタンスメソッドとは異なり、クラスに対して直接操作を行うために使用される。
  • クラス変数やクラス全体の設定を変更する際に便利。

クラスメソッドは self. を先頭に付けて定義し、呼び出す際には クラス名.メソッド名 と書きます。

class クラス名
  def self.クラスメソッド名 # クラスメソッドの定義
    # クラスメソッドの処理
  end
end

# クラスメソッドの呼び出し
クラス名.クラスメソッド名 # selfはつかない

実際のコードの例を見てみましょう。

以下のコードでは、クラスメソッドを使用してクラス変数を管理します。

class User
  @@user_count = 0		# クラス変数の定義
  def initialize(name)	# イニシャライザ
    @name = name
    @@user_count += 1
  end
  def self.get_user_count	# クラスメソッドget_user_countの定義
    puts "現在のユーザー数: #{@@user_count}"
  end
end

# クラスメソッドの呼び出し(まだインスタンス生成していない)
User.get_user_count		# Userクラスのget_user_countメソッドの呼び出し

# インスタンス生成
user = User.new("Alice")	
User.get_user_count		# Userクラスのget_user_countメソッドの呼び出し
# user.get_user_countと書いてはいけない(インスタンスからクラスメソッドは呼び出せない)

このコードを実行すると以下のように出力されます。

現在のユーザー数: 0
現在のユーザー数: 1

クラス変数とクラスメソッドを使ったコード例

クラス変数とクラスメソッドを組み合わせると、より実践的な機能を実現できます。

例えば商品の在庫を管理する簡単なシステムを以下のように作成できます。

class Inventory
  @@items = {} # クラス変数としてハッシュを定義

  def self.add_item(name, quantity)	# クラスメソッド
    if @@items[name]
      @@items[name] += quantity		# 既存のアイテムがあれば在庫を追加
    else
      @@items[name] = quantity		# 新しいアイテムであれば在庫を設定
    end
  end

  def self.get_items # クラスメソッド: 現在の在庫リストを返す
    @@items
  end
end

# クラスメソッドを使用して在庫を管理
Inventory.add_item("りんご", 10)	# "りんご"を10個追加
Inventory.add_item("バナナ", 20)	# "バナナ"を20個追加
Inventory.add_item("りんご", 5)	# 既存の"りんご"に5個追加(合計15個)

puts Inventory.get_items # 現在の在庫リストを出力: {"りんご"=>15, "バナナ"=>20}

この例では、在庫管理システムをクラスメソッドとクラス変数で効率的に実現しています。

ハッシュについて復習しい人は↓↓の記事を参照してください。

あわせて読みたい
【Ruby】Lesson4-8|ハッシュでキーと値のデータを管理しよう
【Ruby】Lesson4-8|ハッシュでキーと値のデータを管理しよう

まとめ|クラス共通の機能を使いこなそう

【初心者向け】Rubyのオブジェクト指向を分かりやすくまとめた概念図。 特にクラスの継承、オーバーライド、モジュール、ミックスイン、インスタンス生成の関係性を視覚的に理解できるようまとめている。

クラス変数とクラスメソッドは、Rubyのクラス全体で共通のデータや機能を管理する強力な手段です。

これらを使いこなすことでクラス設計をシンプルかつ効率的に行えるようになります。

練習問題|貸出管理プログラムでクラス共有の使い方を学ぼう

クラス変数とクラスメソッドをしっかりと身に着けるため、練習問題に挑戦しましょう。

貸出処理を通じてクラスの役割を理解しよう

図書館の本の貸し出し管理を行うプログラムを作成しましょう。

プログラムでは以下の機能を持つクラス Library を定義し、本の貸し出し状況を記録したり確認したりすることができるようにします。

貸し出し中の本の情報はクラス変数に保存し、クラスメソッドを通じて操作しましょう。

以下の要件に従ってコードを完成させてください。

  1. クラス変数 @@borrowed_books を定義し、本のタイトルと借りた人を保存すること。
  2. 本を貸し出すクラスメソッド borrow_book(title, person) を作成すること。
    • 本がすでに貸し出されている場合、その旨を表示すること。
    • まだ貸し出されていない場合、本のタイトルと借りた人を @@borrowed_books に追加し、その情報を表示すること。
  3. 現在貸し出し中の本を一覧表示するクラスメソッド show_borrowed_books を作成すること。
    • 貸し出し中の本がない場合、その旨を表示すること。
  4. 本を返却するクラスメソッド return_book(title) を作成すること。
    • 返却された本を @@borrowed_books から削除し、その旨を表示すること。
    • 返却する本が貸し出されていない場合、その旨を表示すること。

ただし、以下のような実行結果となること。

本 'Ruby入門' を 田中 さんに貸し出しました。
本 'Python基礎' を 佐藤 さんに貸し出しました。
本 'Ruby入門' はすでに貸し出されています。
貸し出し中の本一覧:
Ruby入門: 田中 さん
Python基礎: 佐藤 さん
本 'Ruby入門' が返却されました。
本 'Java入門' は貸し出されていません。
貸し出し中の本一覧:
Python基礎: 佐藤 さん

【ヒント】自力で解くのが難しい人へ

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

Q
ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。

1:クラス Library の定義
  □ クラス変数 @@borrowed_books をハッシュとして初期化
2:クラスメソッド borrow_book の定義
  □ @@borrowed_books に title が存在するかを確認
  □ □ 真の場合、"本 '#{title}' はすでに貸し出されています。" を出力
  □ □ 偽の場合、@@borrowed_books に title をキー、person を値として追加
  □ □ "本 '#{title}' を #{person} さんに貸し出しました。" を出力
3:クラスメソッド show_borrowed_books の定義
  □ @@borrowed_books が空かどうかを確認
  □ □ 真の場合、"現在、貸し出し中の本はありません。" を出力
  □ □ 偽の場合、"貸し出し中の本一覧:" を出力
  □ □ @@borrowed_books を反復処理し、各本のタイトルと借りた人を出力
4:クラスメソッド return_book の定義
  □ @@borrowed_books に title が存在するかを確認
  □ □ 真の場合、@@borrowed_books から title を削除
  □ □ "本 '#{title}' が返却されました。" を出力
  □ □ 偽の場合、"本 '#{title}' は貸し出されていません。" を出力
5:クラスメソッド borrow_book を呼び出し、本 "Ruby入門" を "田中" さんに貸し出す
6:クラスメソッド borrow_book を呼び出し、本 "Python基礎" を "佐藤" さんに貸し出す
7:クラスメソッド borrow_book を呼び出し、既に貸し出されている本 "Ruby入門" を "鈴木" さんに貸し出そうとする
8:クラスメソッド show_borrowed_books を呼び出し、貸し出し中の本一覧を表示
9:クラスメソッド return_book を呼び出し、本 "Ruby入門" を返却
10:クラスメソッド return_book を呼び出し、貸し出されていない本 "Java入門" を返却しようとする
11:クラスメソッド show_borrowed_books を呼び出し、貸し出し中の本一覧を再表示

Q
ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

class Library
  # クラス変数:貸し出し中の本のリスト
=begin
【穴埋め問題1】
ここで貸し出し中の本の情報を保存するためのクラス変数 @@borrowed_books をハッシュとして初期化するコードを書いてください。
=end

  # クラスメソッド:本を貸し出す
  def self.borrow_book(title, person)
=begin
【穴埋め問題2】
ここで貸し出し中の本の情報を確認し、貸し出し可能かどうかを判定するコードを書いてください。
=end
  end

  # クラスメソッド:貸し出し状況を表示する
  def self.show_borrowed_books
=begin
【穴埋め問題3】
ここで貸し出し中の本のリストを出力するコードを書いてください。
貸し出し中の本がない場合は、「現在、貸し出し中の本はありません。」と出力してください。
=end
  end

  # クラスメソッド:本を返却する
  def self.return_book(title)
=begin
【穴埋め問題4】
ここで指定された本を返却し、クラス変数 @@borrowed_books から削除するコードを書いてください。
=end
  end
end

# 動作確認コード
Library.borrow_book("Ruby入門", "田中")
Library.borrow_book("Python基礎", "佐藤")
Library.borrow_book("Ruby入門", "鈴木") # 重複チェック

Library.show_borrowed_books

Library.return_book("Ruby入門")
Library.return_book("Java入門") # 存在しない本の返却

Library.show_borrowed_books

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

この問題の解答例と解説

この問題の正解コードとその解説は以下の通りです。

クリックして開いて確認してください。

Q
正解コード
class Library
  # クラス変数:貸し出し中の本のリスト
  @@borrowed_books = {}

  # クラスメソッド:本を貸し出す
  # 本のタイトル(title)と借りた人(person)を登録
  def self.borrow_book(title, person)
    if @@borrowed_books[title]
      puts "本 '#{title}' はすでに貸し出されています。"
    else
      @@borrowed_books[title] = person
      puts "本 '#{title}' を #{person} さんに貸し出しました。"
    end
  end

  # クラスメソッド:貸し出し状況を表示する
  def self.show_borrowed_books
    if @@borrowed_books.empty?
      puts "現在、貸し出し中の本はありません。"
    else
      puts "貸し出し中の本一覧:"
      @@borrowed_books.each do |title, person|
        puts "#{title}: #{person} さん"
      end
    end
  end

  # クラスメソッド:本を返却する
  def self.return_book(title)
    if @@borrowed_books[title]
      @@borrowed_books.delete(title)
      puts "本 '#{title}' が返却されました。"
    else
      puts "本 '#{title}' は貸し出されていません。"
    end
  end
end

# 動作確認コード
Library.borrow_book("Ruby入門", "田中")
Library.borrow_book("Python基礎", "佐藤")
Library.borrow_book("Ruby入門", "鈴木") # 重複チェック

Library.show_borrowed_books

Library.return_book("Ruby入門")
Library.return_book("Java入門") # 存在しない本の返却

Library.show_borrowed_books
Q
正解コードの解説

コードをブロックごとに分割して解説します。

クラスの定義とクラス変数

class Library
  @@borrowed_books = {}
  • class LibraryLibrary という名前のクラスを定義しています。
    クラスはオブジェクト指向プログラミングの基本的な構造で、データや動作をまとめることができます。
  • @@borrowed_books:クラス変数として定義されています。
    クラス変数はクラス全体で共有されるためどのメソッドからもアクセスできます。
    このプログラムでは、貸し出し中の本の情報を管理するために使用します。

本を貸し出すメソッド

  def self.borrow_book(title, person)
    if @@borrowed_books[title]
      puts "本 '#{title}' はすでに貸し出されています。"
    else
      @@borrowed_books[title] = person
      puts "本 '#{title}' を #{person} さんに貸し出しました。"
    end
  end
  • def self.borrow_book:クラスメソッドの定義です。クラスメソッドは Library.borrow_book のようにクラスから直接呼び出すことができます。
  • if @@borrowed_books[title]:貸し出し中の本がすでにリストに存在するかを確認します。
  • @@borrowed_books[title] = person:新しい貸し出し情報をクラス変数に登録します。
  • puts:操作の結果をコンソールに表示します。

貸し出し状況を表示するメソッド

  def self.show_borrowed_books
    if @@borrowed_books.empty?
      puts "現在、貸し出し中の本はありません。"
    else
      puts "貸し出し中の本一覧:"
      @@borrowed_books.each do |title, person|
        puts "#{title}: #{person} さん"
      end
    end
  end
  • if @@borrowed_books.empty?:貸し出し中の本がない場合の処理を実行します。
  • @@borrowed_books.each:ハッシュのデータを反復処理して、各本のタイトルと借りた人を出力します。

本を返却するメソッド

  def self.return_book(title)
    if @@borrowed_books[title]
      @@borrowed_books.delete(title)
      puts "本 '#{title}' が返却されました。"
    else
      puts "本 '#{title}' は貸し出されていません。"
    end
  end
  • @@borrowed_books.delete(title):指定されたタイトルの本をリストから削除します。
  • puts:返却処理の結果を表示します。

動作確認コード

Library.borrow_book("Ruby入門", "田中")
Library.borrow_book("Python基礎", "佐藤")
Library.borrow_book("Ruby入門", "鈴木")
Library.show_borrowed_books
Library.return_book("Ruby入門")
Library.return_book("Java入門")
Library.show_borrowed_books

この部分はクラスメソッドを実行して、プログラムの動作を確認しています。

まとめ

このコードではクラス変数とクラスメソッドを使ったデータ管理の基本を学びました。

クラス変数を利用することでクラス全体で共有される情報を簡単に管理できます。またクラスメソッドはそのクラスに直接関係する操作を実現するために便利です。

このコードを通じてRubyにおけるオブジェクト指向プログラミングの基礎を理解し、今後の応用に役立ててください!

もっと分かりやすいサイトにするために

この記事を読んで「ここが分かりにくかった」「ここが難しかった」等の意見を募集しています。

世界一わかりやすいRuby学習サイトにするため、ぜひ 問い合わせフォーム からご意見下さい。

<<前のページ

Rubyの記事一覧

次のページ>>

FAQ|Rubyのクラス変数とクラスメソッドの使い方

Q
Q1. Rubyでクラス変数を使うときに注意すべき点は何ですか?

クラス変数(@@)はすべてのインスタンス間で共有されるため、意図せず他のオブジェクトに影響を与える可能性があります。多くのインスタンスから同時に変更が行われる場面では、状態管理が複雑になりやすいため、用途を限定して使うのが安全です。

Q
Q2. クラスメソッドはどんなときに使うのが適切ですか?

クラスメソッドは、インスタンスを生成せずにクラス全体に関連する情報を操作・取得したいときに有効です。たとえば、在庫の集計やユーザー数のカウントなど、インスタンスに依存しない処理に適しています。

Q
Q3. クラス変数と定数(CONST)の違いは何ですか?

クラス変数(@@)は変更可能で、実行中に値を更新できますが、定数(CONST)は原則として変更不可で、一度代入したら変更しない前提で使われます。どちらもクラス全体で共有されますが、用途と性質が異なります。

記事URLをコピーしました