麻布十番で働くデータ分析者のブログ

グロースハック、プログラミング、データ分析の色々を発信します

インスタンスメソッドとクラスメソッドの違いに入門してみる その2

f:id:nimi0370376:20171218122830p:plain

インスタンスメソッドとクラスメソッドの違いに入門してみるのその2になります。

前回のエントリは下記からご覧ください。

nimi0370376.hatenablog.com

今回は、selfキーワードやらクラスの継承やらをメモに残しておきます。

selfキーワードに関して

インスタンスの呼び出し

Rubyにはselfキーワードというものがあります。selfはインスタンス自身を表すキーワードです。

以下のコードは、selfなしでnameメソッドを呼び出す場合、self付きでnameを呼び出す場合、直接インスタンス変数を呼び出す場合の3つを試しています。

class User
  attr_accessor :name

  #インスタンスメソッド
  def initialize(name)
    @name = name
  end

  def hello
    # selfなしでnameメソッドを呼び出す
    puts "Hello, I am #{name}."
  end

  def hi
    # self付きでnameメソッドを呼ぶ
    puts "Hi, I am #{self.name}"
  end

  def my_name
    # 直接インスタンス変数へアクセス
    puts "My name is #{@name}"
  end
end

user = User.new('Alice')
user.hello
user.hi
user.my_name

#=> Hello, I am Alice.
#=> Hi, I am Alice
#=> My name is Alice

これはどれも正解です。人によって書き方が異なるでしょう。

ただし、変数を書き換えたり、name=メソッドで呼び出す場合はselfの有無でエラーが起きるので注意が必要です。

クラスメソッドをインスタンスメソッドを呼び出す

実はクラスメソッドをインスタンスメソッドを呼び出すことができます。

クラス名.メソッド

で呼び出すことができます。

クラスの継承

Rubyではクラスを作成すると継承することができます。 上位のクラスをスーパークラスと呼び、継承をする側をサブクラスと呼びます。

クラスを継承する場合は、下記のように書きます。

class subclass < superclass
end

また、クラスを継承した場合は、アクセサメソッドを省略することができます。

class Product
  attr_accessor :name,:price
  
  def initialize(name,price)
    @name = name
    @price = price
  end
end

product = Product.new('a great movie',1000)
product.name
product.price

#クラスを継承する
class DVD < Product
  #nameとpriceはスーパークラスでattr_accessorが設定されているので定義不要
  attr_accessor :running_time
  
  def initialize(name,price,running_time)
    @name = name
    @price = price
    @running_time = running_time
  end
end

dvd = DVD.new('a great movie',1000,120)
dvd.name
dvd.price
dvd.running_time

またいちいちinitializeを定義しなくても、superメソッドを使うとそのまま利用することができます。

class DVD < Product
    #省略

    def initialize(name,price,running_time)
        super(name,price)
        @running_time = running_time
    end
end

メソッドの公開レベル

privateメソッドについて

Rubyのメソッドにはpublicメソッドとprivateメソッドがあります。

privateメソッドは、クラスの外からは呼び出せず、クラスの内部でのみ利用できるメソッドだと言えます。

class User
  def initialize(my_name)
    @my_name = my_name
  end
  
  #ここから下はprivateメソッド
  private
  
  def hello
    puts 'Hello'
  end
end

user = User.new('Bob')
user.hello #=> エラー

メソッドレベルを後から変更

実はpublicメソッドで定義したメソッドを後からprivateメソッドに変更することも可能です。

class User
  #publicメソッドとして定義
  
  def foo
    puts 'foo'
  end
  
  def bar 
    puts 'bar'
  end
  
  #公開レベルを変更する
  private :foo, :bar
  
  #bazはpublicメソッド
  def baz
    puts 'baz'
  end
end

また他のオブジェクトでは使いたいけど、一般公開したくない場合はprotectedメソッドというのもあります。 それぞれの用途に合わせて使い分ける必要があるでしょう。

変数について

最後はクラスインスタンス変数とクラス変数について紹介します。

インスタンスメソッドとクラスメソッドがあるように、変数にも2種類存在します。

クラスインスタンス変数

クラスインスタンス変数は、インスタンスの作成とは無関係にクラス自身が保持しているデータを表します。

class Product
  # クラスインスタンス変数
  @name = 'Product'
  
  def self.name
    #クラスインスタンス変数
    @name
  end
  
  def initialize(name)
    #インスタンス変数
    @name = name
  end
  
  def name
    #インスタンス変数
    @name
  end
end

クラスインスタンス変数は、スーパークラスとサブクラスに別々の内容が管理されます。これはクラス自身にデータを管理させるという管理方法を再諾しているからです。

クラス変数

Rubyにはクラスメソッド内でもインスタンスメソッド内でも共有され、なおかつスーパークラスとサブクラスでも共有される変数も存在します。

それがクラス変数で、@@から始めるのが特徴です。

class Product
  @@name = 'Product'
  
  def self.name
    @@name
  end
  
  def initialize(name)
    @@name
  end
  
  def name
    @@name
  end
end

class DVD < Product
  @@name = 'DVD'
  
  def self.name
    @@name
  end
  
  def upcase_name
    @@name.upcase
  end
end

#DVDクラスを定義した時点で、@@nameがDVDに変更される

Product.name #=> "DVD"
DVD.name #=> "DVD"

それぞれの変更状況などを見て、使い分ける必要がありそうです。