1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Ruby】特異メソッドって?使いどころや設計思想まで追ってみた

1
Last updated at Posted at 2026-09-23

先日モブプロでこんな感じのclassを書いていて、「特異メソッド」「特異メソッド」と言われ、(あれ...これってクラスメソッドじゃなかったけ...?)となったので、調べました。

class Foo
  class << self
    def bar
      puts "bar"
    end
  end
end

A.結論どっちも正解です。 特異メソッドであり、クラスメソッドでした。

特異メソッドとクラスメソッド

Ruby4.0の公式リファレンスを見てみましょう。

特異メソッド

特異メソッドとはクラスではなくある特定のオブジェクトに固有のメソッドです。

def foo.test
  print "this is foo\n"
end

fooという特定のオブジェクトだけがtestというメソッドを持っています。

クラスメソッド

Ruby におけるクラスメソッドとはクラスの特異メソッドのことです。Ruby では、クラスもオブジェクトなので、普通のオブジェクトと同様に特異メソッドを定義できます。

冒頭のFooクラスの定義は、以下のように書くこともできます。

class Foo
  def self.bar
    puts "bar"
  end
end

ここでいうselfはFooというクラスオブジェクト自身です。
つまり、self.barはFooクラスオブジェクトに対する特異メソッドに他ならないということがよく分かります。

特異メソッドの使いどころ

普通のインスタンスメソッドはそのクラスのすべてのインスタンスで使えますが、特異メソッドは特異クラスに定義され、そのオブジェクトでしか使えないため、クラス及び他のインスタンスに影響しないという利点があります。

特異メソッドの使いどころとしては、このようなユースケースが考えられます。

クラスメソッド

日常の開発で最もよく目にする特異メソッドの形態です。インスタンスを生成せずにメソッドを呼び出したいときに使うものとざっくり理解していましたが、実のところ使うケースとしては以下のふたつにまとめられそうです。

  1. インスタンスを生成するものではない
  2. 通常のコンストラクタとは別に意味のある生成インターフェースからインスタンスを生成したい

インスタンスを生成するものではない

クラスのメタ情報取得やインスタンス生成前の外部入力の検証など、特定のオブジェクトに依存しない処理です。

クラスのメタ情報はRuby自身がすでに持っていて、自ら定義することはあまりないですかね。
何か値を返すだけなら定数で良さそうに思います。

class User
end

User.ancestors
# => [User, Object, Kernel, BasicObject]

外部入力などインスタンスを生成する前に値を検証したいということがあるかもしれません。

class User
  ROLES = %i[guest member admin].freeze

  def self.valid_role?(role)
    ROLES.include?(role)
  end

  def self.admin_role?(role)
    role == :admin
  end
end
User.valid_role?(:admin) # => true
User.valid_role?(:owner) # => false

通常のコンストラクタとは別に意味のある生成インターフェースからインスタンスを生成したい

例えば、検索・取得。ActiveRecordに慣れているので、こう書きたくなります。

user = User.find(1)

あとはファクトリメソッド。
通常の new とは別に、意味のある名前をつけてインスタンスを生成したいケースです。

class User
  attr_reader :name, :role

  def initialize(name, role)
    @name = name
    @role = role
  end

  def self.guest
    new("Guest", :guest)
  end

  def self.admin(name)
    new(name, :admin)
  end
end
guest = User.guest
admin = User.admin("Alice")

User.guest はコンストラクタを経由するとこのような書き方になりますが、ファクトリメソッドを使うとより直感的でコードの意図が伝わりやすくなります。

guest = User.new("Guest", :guest)

モックやスタブ

特定のテストでのみオブジェクトの挙動を差し替えたい場合、特異メソッドで上書きすることができます。
ただ、実際にはRSpecなどのテストフレームワークの仕組みを使うと思うので、この書き方をすることは稀でしょう。

client = ApiClient.new

def client.fetch
  { status: 200, body: "fake" }
end

なぜRubyには特異メソッドがあるのか?

Rubyの重要な設計方針のひとつに 「オブジェクトの個性化(Object individuation)」 があります。
これは、同じクラスから生成されたオブジェクトであっても、個々のオブジェクトが固有の振る舞いを持てるようにする仕組みです。

よくオブジェクト指向の説明で以下のようなコードを見かけます。

class Person
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def introduce
    puts "こんにちは、私は#{@name}です。#{@age}歳です。"
  end
end

john = Person.new("John", 20)
john.introduce
# => こんにちは、私はJohnです。20歳です。

akane = Person.new("Akane", 16)
akane.introduce
# => こんにちは、私はAkaneです。16歳です。

現実世界ではJohnとAkaneは同じ人間として生まれたとしても、異なる道を歩んで成長し、まったく違う個性を持っているはずです。

オブジェクトの生成以降、独自の発展をしていくというのはある種自然なことであり、Rubyでそれを可能にする機能として特異メソッドが用意されています。

なにに使えるかというよりも自然の摂理としてあるものと理解しておくのがしっくりきます。

特異メソッドが本来の意味で使われることはあまりない?

なにに使えるかというよりも自然の摂理としてあるものと理解しておくのがしっくりきます。

これあまり深く考えずに書いてしまった後に思い至ったのですが、どうやら私は特異メソッドを本来の意味合いで使うことはあまりないらしいと思っているようです。

ここをもう少し深掘りしてみたいと思います。

特異メソッドの使いどころとしてクラスメソッドとモック・スタブのふたつを挙げました。
ただ、そのどちらも「生成されたオブジェクトが独自の個性を持っていく」のとは少し違うような気がします。

クラスメソッドでいうとファクトリメソッドが特異メソッドの本来の意味での使い方に近そうですが、これはインスタンス生成後ではなく、生成時の個性付与です。
また、モックやスタブは例外的な扱いであり、自然の摂理としての個性とは異なります。

先ほど取り挙げたPersonクラスとJohnやAkaneのオブジェクトで見ても、プログラミング世界においてJohnオブジェクト生成後に特異メソッドを生やしていくということはまあないだろうと思います。
やるとしてもサブクラスあたりを使うのではないでしょうか?

考察してみると、特異メソッドがあまり使われない理由として以下の理由が考えられます。

  • プログラミングが現実世界の特定の問題領域を抽象化してソフトウェア上に構築する以上、具体を載せていくということをそもそもあまりしない
  • 特定のインスタンスにだけ特異メソッドを後から生やす、いわゆるモンキーパッチ的な使い方は、状態管理が複雑になりコードの予測可能性が下がるためアンチパターンになりやすい

設計思想と実務のズレみたいなものがあって面白いですね。

まとめ

当初の疑問点である、特異メソッドとクラスメソッドの関係はあっさり解決してしまいましたが、関連して疑問に思ったことを調べていくなかで、Rubyの設計思想や実際のアプリケーション開発で求められる可読性や保守性とのズレがあるということも分かり、一段と解像度が高まったような気がします。

参考

他にも参考になったWebサイトたち

1
0
1

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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?