これまでのレッスンでクラスとは、オブジェクトの種類(型)だと学んできました。そして、あらゆるオブジェクトは何らかのクラスに属していて、このことを〇〇(クラス名)クラスのインスタンス(オブジェクト)という呼び方をすることも学びました。
このクラスとインスタンスの関係性はよく、たい焼き器とたい焼きの関係を例に表されています。
これまでのレッスンでクラスとは、オブジェクトの種類(型)だと学んできました。そして、あらゆるオブジェクトは何らかのクラスに属していて、このことを〇〇(クラス名)クラスのインスタンス(オブジェクト)という呼び方をすることも学びました。このクラスとインスタンスの関係性はよく、たい焼き器とたい焼きの関係を例に表されています。
また、クラスは設計図のようなものとも表現されることがあります。これは、設計図に書いてある決まりに従い作られたオブジェクトというような感じで、クラスとオブジェクトの関係性を分かりやすく表しています。
では、オブジェクトがどのクラスに属しているかを見ていきましょう。
オブジェクト | クラス |
数値 | Numeric |
文字列 | String |
配列 | Array |
ハッシュ | Hash |
正規表現 | Regexp |
ファイル | File |
シンボル | Symbol |
〇〇というオブジェクトが〇〇というクラスに属しているか(インスタンスか)ということを調べたい場合は、以下のように調べます。
name = "山田"
p name.instance_of?(String)
#=> true
このように「instance_of?」というメソッドで確認します。結果は「true(真)」か「false(偽)」で返ってきます。
継承とは、定義済みのクラスを継承した新しいクラスを作成するという事です。既存のクラスを親とし子のクラスを新たに作るといったイメージです。
スーパークラスには共通で使いたい機能を持たせ、サブクラスではそのサブクラスのみで使いたい機能を持たせるという形になります。この他にも、継承を行う事によりスーパークラスで定義した機能をサブクラスで定義し直し違う役割を持たせたり、スーパークラスでの機能に追加機能をサブクラスで持たせるなどすることが出来ます。
文字列オブジェクトの属する「String」クラスや、配列オブジェクトの属する「Array」クラスなど、ruby内の全てのクラスは「BasicObject」というクラスのサブクラスです。これらは、あらかじめ用意されているクラスであり「組み込みクラス」と呼ばれるものです。
では組み込みクラスには、どのようなものが有るのか、また組み込みクラスの関係性どうなっているのかを以下の図を見て学びましょう。
オブジェクトがクラスに属しているか調べるには「is_a?」というメソッドで調べます。
name = "山田"
p name.is_a?(String)
# => true
name(オブジェクト)は、stringに属しているか? という事ですね。前セクションで「instance_of?」を学んだと思いますが、この「is_a?」との違いについて、以下図を使ってご説明します。
このような関係性にある文字列オブジェクトがあるとします。そして、クラスに属しているか調べるときに以下のようなコードが使えるでしょう。
str = "a"
p str.instance_of?(String)
#=> true
p str.instance_of?(BasicObject)
#=> false
p str.is_a?(String)
#=> true
p str.is_a?(BasicObject)
#=> true
実行し結果を見てみてください。結果は「true(真)」か「false(偽)」どちらかになりますが、「is_a?」であれば上記画像でいうとオブジェクトが子クラスであるStringに属しているかに加え、子クラスを飛び越え、親クラスであるBasicObjectに属しているかも調べることが出来ます(trueになる範囲が広い)。
逆に「instance_of?」はStringクラスがBasicObjectに属していても、直接属しているStringクラスまでしか調べることが出来ません。
クラスを定義する際には、様々な規則に従い作成する必要があります。また、構文やメソッドなども出てまいりますので、1つ1つ学んでいきましょう。
クラス定義する際には、この「class文」というものを使います。構文は以下のようになります。
class クラス名
定義内容
end
クラス名の1文字目は、大文字でなければなりません。
class User
def welcome
puts "welcome!"
end
end
上記の中のdef welcomeのように、class文の中(class クラス名~end)にメソッドを定義したとき、そのメソッドはインスタンスメソッドとなります。
前セクションでも登場したdef welcomeとは違い、この「initializeメソッド」はオブジェクトの初期化の処理のメソッドです。「クラス名.new」のコードを実行したとき、initializeメソッドが呼び出されます。では、皆さんも以下例を実行してみましょう!initializeメソッドとクラス名.newが関連づいていることが分かると思います。
class User
def initialize(user_name = "new_user")
@name = user_name
end
def welcome
puts "welcome, #{@name}!"
end
end
yuki = User.new("yuki")
gest = User.new()
yuki.welcome
#welcome, yuki!
前セクションで、「@name」という変数が出てきました。これは、インスタンス変数と呼ばれる変数です。インスタンス変数は「@」で始まります。スコープについてですが以下図をご覧ください。
ローカル変数が定義したメソッド外では参照できないのに対し、インスタンス変数は定義したメソッド外で参照することが可能です。つまり、インスタンス変数はクラス内の全メソッドが有効範囲となります。また、インスタンス変数は、オブジェクトごとにそれぞれ異なる値を保有できます。
インスタンス変数はクラス外では、参照したり、値部分に新たな別の値を代入したりすることは出来ません。ですが、参照・変更のためのメソッドを定義すれば可能になるのです。では以下追加部分を記述し実行してみましょう。
ーーーー追加部分ーーーー
def name_sanshou
@name
end
def change_name(new_name)
@name = new_name
end
puts yuki.name_sanshou
yuki.change_name("yuki_tanaka")
yuki.welcome
ーーーーーーーー
class User
def initialize(user_name = "new_user")
@name = user_name
end
def welcome
puts "welcome, #{@name}!"
end
def name_sanshou
@name
end
def change_name(new_name)
@name = new_name
end
end
yuki = User.new("yuki")
yuki.welcome
#welcome, yuki!
puts yuki.name_sanshou
#yuki
yuki.change_name("yuki_tanaka")
#=> "yuki_tanaka"
yuki.welcome
#welcome, yuki_tanaka!
このようにすればクラス外で参照・変更を行う事が出来るようになるわけですが、参照・変更したいインスタンス変数が複数ある場合は、コードがとても分かりにくくなってしまいます。そういった場合に、使うと良いのが「アクセスメソッド」です。アクセスメソッドには3種類あります。以下表をご覧ください。
呼び方 | 定義 | 出来ること |
リーダー / ゲッター | attr_reader :変数名 | 参照のみ |
ライター / セッター | attr_writer :変数名 | 変更のみ |
アクセサー / アクセスメソッド | attr_accessor :変数名 | 参照・変更の両方 |
このように、1行で書けてしまうので簡単でかつ見やすいですね。では、以下をアクセスメソッドにしてみましょう。
def name_sanshou
@name
end
def change_name(new_name)
@name = new_name
end
name_sanshoは変数nameを参照するためのもので、change_name(new_name)
は変数nameを変更するためのものです。これをアクセスメソッドにすると、
attr_accessor :name
となります。これで変数nameを参照・変更するためのアクセスメソッドであるnameというメソッドができました。
メソッドのレシーバを参照するには、この「self」という変数を使います。
class User
attr_accessor :name
.
.
.
def welcome
puts "welcome, #{self.name}!"
end
end
yuki.welcome
という書き方になります。この場合のレシーバは「yuki」です。
こちらはレシーバが「クラス」そのものになります。「クラス」が受け取ることのできる命令という事になります。では、定義の仕方についてみていきましょう。
class << クラス名
def メソッド名
定義
end
end
「class << クラス名」というように特殊なクラス定義をする形になります。また、「class クラス名」のあとに「class << self」と書く方法もあります。この方法が一般的に最も使われています。
class クラス名
class << self
def メソッド名
定義
end
end
end
もしくは、「def クラス名.メソッド名」というように書くこともできます。
def クラス名.メソッド名
定義
end
また、この書き方の場合にも「self」を使うパターンがあります。
def self.メソッド名
定義
end
「class << self」を特異クラス定義と呼び、特異クラス定義内で定義したメソッドを特異メソッドと呼びます。
上記の特異クラス定義をすると、特定のオブジェクト専用の特異メソッドというものを定義する事が出来ます。例として、「aisatsu_1」という変数に代入する「こんにちは」という文字列オブジェクトでのみ「welcome」という特異メソッドを使用してみます。
aisatsu_1 = "こんにちは"
aisatsu_2 = "こんにちは"
class << aisatsu_1
def welcome
puts "#{self}、ようこそいらっしゃいました。"
end
end
p aisatsu_1.welcome
#こんにちは、ようこそいらっしゃいました
p aisatsu_2.welcome
#NoMethodError: undefined method `welcome' for "こんにちは":String
aisatsu_1でのみwelcomeメソッドが呼び出されていればOKです!
インスタンス変数とは、オブジェクトごとで異なる値を持つことのできるものでした。それに対しクラス変数とは、クラス内で値が共有されるので、どのオブジェクトでも値は同じものになります。また、有効範囲(スコープ)は、クラス内(クラス内のメソッド内含む)と、クラスのインスタンスです。書き方は変数名の前に「@@」を付けます。
class Test
@@aisatsu = "hello!"
def test_method
puts @@aisatsu
end
end
hello = Test.new
hello.test_method
#hello!
rubyではメソッドに以下3種類のアクセス制限の設定が付いています。
public | クラス内外 |
private | クラス内のみ |
protected | クラス内とサブクラス |
何も指定しなければ、全てのメソッドはデフォルトで「public」となります。(initalizeメソッドだけは、「private」となります。publicに変更することは出来ません。)アクセス制限を変更する際は以下のように書きます。
アクセス制限種類 :メソッド名
記載する場所は2パターンあります。
class クラス名
def test(メソッド名)
定義
end
private :test
end
この場合は「test」というメソッドを指定し、「private」と設定しています。
class クラス名
private
def test(メソッド名)
定義
end
def test_2(メソッド名)
定義
end
end
この場合ですと、「private」以降のメソッドが全て「private」となります。
既存のクラス(組み込みクラスなど)にメソッドを追加し、クラスを拡張するという事も可能です。では、Stringクラスにメソッドを追加してみましょう。
class String
def kurikaeshi_kotoba
puts self + self
end
end
"もし".kurikaeshi_kotoba
#もしもし
文字列が2回繰り返されていればOKです。
このレッスンの始めの方で継承について学びました。このセクションでは継承の仕方についてみていきましょう。書き方は以下のようになります。
class サブクラス名 < スーパークラス名
定義
end
では、社員クラス(スーパークラス)、社長クラス(サブクラス1)、従業員クラス(サブクラス2)という例を使い実際にコードを実行してみましょう。
class Personnel
def shain
puts "私たちは〇〇社の社員です"
end
end
class President < Personnel
def shachou
puts "私は社長です"
end
end
class Worker < Personnel
def shain
puts "私たちは〇〇社の社員であり従業員です"
end
end
personnel = Personnel.new
president = President.new
worker = Worker.new
personnel.shain
#私たちは〇〇社の社員です
president.shain
#私たちは〇〇社の社員です
worker.shain
#私たちは〇〇社の社員であり従業員です
このようにスーパークラスで定義したメソッドをサブクラスにて書き換えたり、スーパクラスで定義したメソッドを呼び出したり出来ます。
・alias
既存メソッドに他の名前を付けたい際に、この「alias」を使用します。書き方は以下のようになります。
alias メソッド名(新) メソッド名(元)
また、以下のようにシンボルで指定する事も可能です。
alias :メソッド名(新) :メソッド名(元)
では使い道について以下例を参考に学びましょう。
def aisatsu
puts "Hello"
end
alias aisatsu aisatsu_nihongo
def aisatsu_nihongo
aisatsu
puts "は、日本語で言うとこんにちは"
end
aisatsu_nihongo
このように、元の名前のメソッドは消えるわけではないので、呼び出すことが可能です。
・undef
定義済みのメソッドを削除したい際などに使用します。書き方は以下のようになります。
undef メソッド名
また、以下のようにシンボルで指定する事も可能です。
undef :メソッド名
では、スーパークラスで定義したメソッドをサブクラスではないものとするという例を以下のように実行してみましょう。
class Test
def foo
puts 'hello'
end
end
class Test_sub < Test
undef foo
end
test = Test.new
test_sub = Test_sub.new
test.foo
#hello
test_sub.foo
#NoMethodError: undefined method `foo' for #<Test_sub:0x000000009b0d98>
サブクラスでのみメソッドfooが削除されていれば成功です。
クラスとは設計図の様なものです。クラスから作成されたオブジェクトはインスタンスと呼ばれ、親クラスには共通の機能、その機能を受け継いで更に独自の機能を持つ子クラスというように継承を行う事が出来ます。
無料ビデオ講座のお知らせ
Skillhub [スキルハブ]では無料の動画講座を多数公開しています。他校だと数万円するような講座が無料で受講できます。