【Ruby】レッスン5-04:クラス変数とクラスメソッドを理解しよう

記事内に商品プロモーションを含む場合があります

この記事で学べる知識:クラス変数とクラスメソッド

この記事の練習問題を解くために必要な知識:
基礎文法、制御構造、メソッド、コレクション(レッスン1~4)クラスの定義と使用イニシャライザアクセスメソッドクラス変数とクラスメソッドprivateメソッド正規表現クラスの継承ファイル操作オーバーライドモジュールの定義と使用ミックスイン

<<前のページ Ruby記事一覧 次のページ>>

Rubyの文法「クラスメソッドとインスタンスメソッド」とは

ここではクラスメソッドとインスタンスメソッドの意味や使い方を学習します。必要ない方はここをクリックして練習問題へ飛びましょう。



Rubyのオブジェクト指向プログラミングでは、「クラス変数」と「クラスメソッド」を使用することでクラス全体で共有されるデータや機能を扱うことができます。

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

クラス変数とは

クラス変数はクラス全体で共有される変数であり、クラス内のすべてのインスタンスが共通してアクセス可能なデータを保存するために使用します。

クラス変数は@@から始まる記法で定義します。

特徴

  • クラス全体で共有されるため、どのインスタンスからでも同じ値にアクセスできる。
  • クラスそのものやその子クラスからも参照可能。

※子クラスについてはLesson5-7で学習予定

使用例

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

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

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

  def self.user_count  # self.user_countメソッド(クラスメソッド)の定義
    @@user_count       # このメソッドの戻り値としてクラス変数を設定
  end
end

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

puts User.user_count # インスタンスが2回生成された後なので、出力は2

この例では@@user_countがクラス全体で共有され、インスタンスが作成されるたびにカウントが増加します。

クラスメソッドについては以下で説明します。

クラスメソッドとは

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

クラスメソッドはself.を先頭に付けて定義します。

特徴

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

使用例

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

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

  def initialize(name)
    @name = name       # インスタンス変数の初期化
    @@user_count += 1
  end

  def self.get_user_count # クラスメソッドget_user_countの定義
    "現在のユーザー数: #{@@user_count}"
  end
end

# クラスメソッドの呼び出し
puts User.get_user_count  # Userクラスのget_user_countメソッドの呼び出し

user1 = User.new("Alice") # インスタンス生成
puts User.get_user_count  # Userクラスのget_user_countメソッドの呼び出し
# クラスメソッドは、クラス名を使用して呼び出す(self.を付けないよう注意)

使用例:クラス変数とクラスメソッドの組み合わせ

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

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

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のクラス全体で共通のデータや機能を管理する強力な手段です。

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

クラス変数とクラスメソッドの練習問題

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

プログラムでは以下の機能を持つクラス 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からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

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

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

1:クラス Library の定義
  □ クラス変数 @@borrowed_books をハッシュとして初期化
2:クラスメソッド borrow_book の定義
  □ @@borrowed_bookstitle が存在するかを確認
  □ □ 真の場合、"本 '#{title}' はすでに貸し出されています。" を出力
  □ □ 偽の場合、@@borrowed_bookstitle をキー、person を値として追加
  □ □ "本 '#{title}' を #{person} さんに貸し出しました。" を出力
3:クラスメソッド show_borrowed_books の定義
  □ @@borrowed_books が空かどうかを確認
  □ □ 真の場合、"現在、貸し出し中の本はありません。" を出力
  □ □ 偽の場合、"貸し出し中の本一覧:" を出力
  □ □ @@borrowed_books を反復処理し、各本のタイトルと借りた人を出力
4:クラスメソッド return_book の定義
  □ @@borrowed_bookstitle が存在するかを確認
  □ □ 真の場合、@@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 を呼び出し、貸し出し中の本一覧を再表示

ヒント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

この問題の穴埋めコードは以上です。

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



練習問題の解答と解説

この問題の一つの正解例とそのコードの解説を以下に示します。

正解コードの例

例えば以下のようなプログラムが考えられます。

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

正解コードの解説

今回のコードは図書館の本の貸し出し状況を管理するプログラムです。

このコードで「クラス変数」と「クラスメソッド」の基本的な使い方を学ぶことができます。

コードの各ブロックを解説していきましょう。

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

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記事一覧 次のページ>>

この記事への質問・コメント

この記事を作成するにあたりAIを活用しています。

問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。






    Rubyのテキスト&問題集トップへ戻る
    トップページへ戻る