クラスは、オブジェクト指向プログラミングの中心となる概念です。 Crystalでは、すべてがオブジェクトです。すべてのオブジェクトには型があり、いくつかのメソッドに応答できます。 クラスはオブジェクトを作るための設計図で、変数のような状態の初期値や、メソッドのような振る舞いの実装を提供します。 オブジェクトはクラスのインスタンスで、すべてのインスタンス変数と状態を保持します。
クラスは、classキーワードを使い、そのあとにUpperCamelCaseで書いたクラス名を続けて定義します。
class Account
end
クラスのインスタンスを作成するには、newメソッドを使ってクラス名を呼び出します。
class Account
end
account = Account.new
上の例では、変数accountはクラスAccountのインスタンスです。
インスタンスを作成するとき、initializeという特別なメソッドがコンストラクターの役割を果たします。
これはインスタンスが作成されるときに呼び出されます。
コンストラクターを使うと、インスタンスの初期状態を設定できます。
initializeメソッドは引数を受け取ることができ、その引数はインスタンスを作成するときに渡します。
class Account
def initialize(number)
5 + number # => 9
end
end
Account.new(4)
initializeメソッドは値を手動で返すことはできません。代わりに、newが新しく作成したインスタンスを返します。
class Account
def initialize(number)
5 + number
end
end
Account.new(4)
# => #<Account:0x7f5dc33dcea0>
インスタンスメソッドは、クラスのインスタンスで利用できるメソッドで、そのインスタンスに対して呼び出せます。
インスタンスメソッドは、defキーワードを使い、そのあとにメソッド名を続けて定義します。
クラス定義の中に定義します。
class Account
def balance
100
end
end
account = Account.new
account.balance # => 100
インスタンス変数は、そのインスタンスのすべてのメソッドで利用できる変数です。
インスタンス変数にアクセスするには、インスタンスメソッドを定義する必要があります。
インスタンス変数はinitializeメソッドで初期化できます。
@を先頭に付けて定義します。
class Account
def initialize
@balance = 100
end
def balance
@balance
end
end
account = Account.new
account.balance
# => 100
インスタンス変数は、クラス定義の中でも定義できます。
class Account
@age = 0
end
インスタンス変数は、initializeメソッドに渡された引数で初期化できます。
Crystalは初期化時に使われる引数の型を推論できないため、型を指定する必要があります。
これについて詳しく知りたい場合は、型推論を読んでみてください。
変数の型を指定するには、:記号のあとに型を書きます。
たとえば、Int32型のbalanceというインスタンス変数を作りたい場合は、@balance : Int32と書きます。
また、Bool型のrainingというインスタンス変数を作りたい場合は、@raining : Boolと書きます。
実装方法はいくつかあります。たとえば、initializeメソッドの引数に型を宣言し、その引数をインスタンス変数に代入する方法です。
class Account
def initialize(balance : Int32)
@balance = balance
end
def balance
@balance
end
end
account = Account.new(1)
account_2 = Account.new(5)
account.balance
# => 1
account_2.balance
# => 5
もう一つの方法は、クラス定義の中で@<variable> : <Type>の形でインスタンス変数の型を宣言する方法です。
class Weather
@raining : Bool
def initialize(raining)
@raining = raining
end
def raining
@raining
end
end
weather = Weather.new(true)
weather.raining
# => true
メソッドはインスタンス変数を変更できます。 これらのメソッドはクラスのインスタンスに対して呼び出せます。 メソッドがインスタンス変数を変更すると、その変更は呼び出したクラスのインスタンスだけに反映されます。
class Account
def initialize(balance : Int32)
@balance = balance
end
def withdraw(amount)
@balance -= amount
end
def balance
@balance
end
end
account = Account.new(10)
account_2 = Account.new(10)
account.balance
# => 10
account_2.balance
# => 10
account.withdraw(5)
account.balance
# => 5
account_2.balance
# => 10
クラスメソッドは、クラスに対して定義されるメソッドで、そのインスタンスに対しては定義されません。
インスタンスの状態に依存しないメソッドを作る手段になります。
クラスメソッドは、defキーワードを使い、そのあとにself.<method name>を続けて定義します。
selfは、selfが呼び出されている名前空間への参照です。
ここでは、クラスAccountを指します。
Account.と書いた場合と同じになりますが、self.を使うのが好ましい書き方です。
class Account
def self.balance
100
end
end
Account.balance
# => 100
友人のJohannesは、DIY(自分で作ること)のハードウェアが大好きです。 Johannesはちょうどジューサーメーカーを作り終えたところで、とてもわくわくしています。 Johannesの目標は、毎朝新鮮なジュースを作れるようになることです。
Johannesのジューサーメーカーには、たくさんのすてきな機能が備わっています。 たとえば、カップにどれだけジュースが入っているかを教えてくれる、組み込みの計量システムです。 マシンがどのくらい動いているかを教えてくれるタイマーもあります。
Johannesはプログラミングが得意というわけではありませんが、このマシンを制御するプログラムを作りたいと思っています。 そこで、手伝ってほしいと頼んできました。
マシンにはデバッグライトが付いています。仕組みは単純で、マシンに電力が供給されていればデバッグライトが点灯します。 プログラムは、デバッグライトが点灯しているときだけ実行されます。
このメソッドは、JuiceMakerという名前のクラスメソッドにします。
trueを返すクラスメソッドJuiceMaker.debug_light_on?を定義します。
JuiceMaker.debug_light_on?
#=> true
マシンの電源が入ると、JuiceMakerというクラスのインスタンスが生成されるようにします。
マシンには、初期化された状態を持たせることにします。
この初期状態には、次の情報を保持させます。
falseになります。カップに入っているジュースの量を引数に取る初期化処理を定義し、初期状態を組み立てます。
この初期状態には、falseに設定されたインスタンス変数@runningと、クラスの初期化時に渡された引数に基づくインスタンス変数@fluidを持たせます。
JuiceMaker.new(5)
#=> #<JuiceMaker:0x10f0b8 @running=false, @fluid=5>
マシンは電源を入れたり切ったりできます。
マシンの電源を入れるメソッドを定義する必要があります。
マシンの電源を入れると、動作状態はtrueに設定されます。
マシンの電源を入れるメソッドJuiceMaker#startを定義します。
juice_maker = JuiceMaker.new(5)
juice_maker.start
juice_maker
#=> #<JuiceMaker:0x10f0b8 @running=true, @fluid=5>
マシンは、自分の状態を教えてくれる必要があります。
マシンが動作中ならtrueを、動作していなければfalseを返します。
マシンの状態を返すメソッドJuiceMaker#running?を定義します。
juice_maker = JuiceMaker.new(5)
juice_maker.start
juice_maker.running?
#=> true
マシンはカップにジュースを追加できます。 追加されたジュースの量は、マシンが把握できます。 ジュースを追加したあとにカップへ入っているジュースの量を知るには、マシンに手助けが必要です。
追加するジュースの量を引数に取り、カップの中のジュースの量を更新するメソッドJuiceMaker#add_fluidを定義します。
juice_maker = JuiceMaker.new(5)
juice_maker.add_fluid(5)
juice_maker
#=> #<JuiceMaker:0x10f0b8 @running=false, @fluid=10>
マシンは電源を入れたり切ったりできます。
マシンの電源を切るメソッドを定義する必要があります。
このメソッドは、マシンが動作しているときだけ呼び出されます。
マシンの電源を切ると、動作状態はfalseに設定されます。
また、電源を切ったあとにカップへ入っているジュースの量を求めるのにも、マシンには手助けが必要です。
マシンは1分あたり5単位のジュースを消費します。
マシンが動作していた分数を引数に取り、電源を切ったあとのカップの中のジュースの量を返すメソッドJuiceMaker#stopを定義します。
juice_maker = JuiceMaker.new(5)
juice_maker.start
juice_maker
#=> <JuiceMaker:0x10f0b8 @running=true, @fluid=5>
juice_maker.stop(1)
#=> #<JuiceMaker:0x10f0b8 @running=false, @fluid=0>