Ruby オブジェクト指向
Rubyは純粋なオブジェクト指向言語で、Rubyにおけるすべてのものはオブジェクトの形で現れます。Rubyのすべての値はオブジェクトであり、最も原始的なものでも、文字列、数値、さらには true や false もオブジェクトです。クラス自体もまたオブジェクトであり、Classクラスのインスタンスです。この章では、Rubyのオブジェクト指向に関連するすべての主要な機能について説明します。
クラスはオブジェクトの形式を指定するために使用され、データ表現とメソッドを組み合わせて、データを整然としたパッケージにまとめます。クラス内のデータとメソッドはクラスのメンバーと呼ばれます。
Ruby クラス定義
クラスを定義するとき、実際にはデータ型の設計図(ブループリント)を定義しています。これは実際にはデータを一切定義するものではなく、クラス名が何を意味するか、つまりクラスのオブジェクトが何で構成され、そのオブジェクトに対してどのような操作を実行できるかを定義します。
クラス定義はキーワードclassclass で始まり、その後にクラス名、最後にendend で区切って、そのクラス定義の終了を示します。例えば、キーワード class を使用して Box クラスを定義する場合は、次のようになります。
慣例により、名前は大文字で始める必要があります。複数の単語が含まれる場合、各単語の先頭は大文字にしますが、その間に区切り文字はありません(例:CamelCase)。
Ruby オブジェクトの定義
クラスはオブジェクトの設計図を提供するため、基本的にオブジェクトはクラスに基づいて作成されます。私たちはnewnew キーワードを使用してクラスのオブジェクトを宣言します。次の文は、クラス Box の2つのオブジェクトを宣言しています。
initialize メソッド
initializeこのメソッドは標準的なRubyのクラスメソッドであり、クラスのコンストラクタです。他のオブジェクト指向プログラミング言語におけるconstructorコンストラクタと同様に機能します。オブジェクトの作成と同時にいくつかのクラス変数を初期化したい場合、initialize メソッドが役立ちます。このメソッドは一連のパラメータを受け取ります。他のRubyメソッドと同様に、このメソッドを使用するときは、その前にdefキーワードを置く必要があります。次のようになります。
インスタンス変数
インスタンス変数はクラスの属性であり、クラスを使用してオブジェクトを作成すると、それらはオブジェクトの属性になります。各オブジェクトの属性は個別に割り当てられ、他のオブジェクトと値は共有されません。クラスの内部では、@ 演算子を使用してこれらの属性にアクセスします。クラスの外部では、いわゆるアクセサメソッドのパブリックメソッドを使用してアクセスします。次に、上で定義したクラスBoxを例として、@width と @height をクラス Box のインスタンス変数とします。
アクセサ(getter) & セッター(setter)メソッド
クラスの外部でクラス内に定義された変数を読み取るために、アクセサ(getter)メソッドを定義してアクセスできます。次の例は、アクセサメソッドの使い方を示しています。
例
試してみる »
上記のコードを実行すると、次の結果が生成されます。
盒子宽度 : 10 盒子高度 : 20
変数値にアクセスするためのアクセサメソッドと同様に、Rubyにはクラスの外部からクラス内に定義された変数にパラメータを渡す方法、いわゆるセッターメソッドが用意されています。定義は次のとおりです。
例
試してみる »
上記のコードを実行すると、次の結果が生成されます。
盒子宽度 : 30 盒子高度 : 50
この2つのメソッドは非常に頻繁に使われるため、Rubyではattr_accessor :variable_name、attr_reader :variable_name、attr_writer :variable_name3つの属性宣言メソッドが定義されています。そのうち:accessor=reader+writer。
同時に注意:変数名の前には必ず:@ を付け、変数名の間は,, で区切ります。
インスタンスメソッド
インスタンスメソッドの定義は他のメソッドの定義と同様に、すべてdefdef キーワードを使用しますが、クラスインスタンスを介してのみ使用できます。次の例に示すとおりです。それらの機能はインスタンス変数へのアクセスに限定されず、ニーズに応じて他の多くのタスクを実行することもできます。
例
試してみる »
上記のコードを実行すると、次の結果が生成されます。
Area of the box is : 200
クラスメソッド & クラス変数
クラス変数は、クラスのすべてのインスタンス間で共有される変数です。言い換えると、クラス変数のインスタンスは、すべてのオブジェクトインスタンスからアクセスできます。クラス変数は2つの @ 文字(@@)をプレフィックスとして持ち、クラス定義内で初期化する必要があります。次の例に示すとおりです。
クラスメソッドdef を使用してdef self.methodname()定義され、クラスメソッドは end 区切り文字で終わります。クラスメソッドはクラス名を伴うclassname.methodname形式で呼び出すことができます。次の例に示すとおりです。
例
試してみる »
上記のコードを実行すると、次の結果が生成されます。
Box count is : 2
to_s メソッド
定義したすべてのクラスにはto_sオブジェクトの文字列表現を返すインスタンスメソッドがあります。次は、width と height に基づいて Box オブジェクトを表す簡単な例です。
例
試してみる »
上記のコードを実行すると、次の結果が生成されます。
String representation of box is : (w:10,h:20)
アクセス制御
Rubyは、インスタンスメソッド保護の3つのレベルを提供します。それぞれpublic、private または protectedです。Rubyはインスタンス変数とクラス変数にはアクセス制御を適用しません。
- Public メソッド:Public メソッドは任意のオブジェクトから呼び出せます。デフォルトでは、メソッドはすべて public ですが、initialize メソッドだけは常に private です。
- Private メソッド:Private メソッドはクラスの外部からアクセスまたは参照できません。クラスメソッドのみがプライベートメンバーにアクセスできます。
- Protected メソッド:Protected メソッドは、クラスとそのサブクラスのオブジェクトからのみ呼び出せます。アクセスもクラスとそのサブクラスの内部でのみ行えます。
次は、これら3つの修飾子の構文を示す簡単な例です。
例
試してみる »
上記のコードを実行すると、次の結果が生成されます。ここでは、最初のメソッド呼び出しは成功しますが、2番目のメソッドは問題を引き起こします。
Area of the box is : 200 test.rb:42: protected method `printArea' called for # <Box:0xb7f11280 @height=20, @width=10> (NoMethodError)
クラスの継承
継承は、オブジェクト指向プログラミングにおける最も重要な概念の一つです。継承により、別のクラスに基づいてクラスを定義できるため、アプリケーションの作成と保守が容易になります。
継承はコードの再利用と高速実行に役立ちます。残念ながら、Ruby は多重継承をサポートしていませんが、Ruby はサポートしていますmixins。mixin は多重継承の特定の実装のようなもので、多重継承ではインターフェース部分のみが継承可能です。
クラスを作成するとき、プログラマーは新しいクラスが既存のクラスのメンバーを継承するように直接指定できます。これにより、新しいデータメンバーとメンバー関数を最初から書く必要がありません。この既存のクラスは基本クラスまたは親クラス、新しいクラスは派生クラスまたは子クラス。
Ruby もサブクラス化の概念を提供します。サブクラス化とは継承のことです。以下の例でこの概念を説明します。クラスを拡張する構文は非常に簡単です。< 文字と親クラスの名前をクラス文に追加するだけです。たとえば、以下はクラスを定義していますBigBoxであるBoxのサブクラス:
例
試してみる »
上記のコードを実行すると、次の結果が生成されます:
Big box area is : 200
メソッドのオーバーロード
派生クラスに新しい機能を追加することはできますが、親クラスで既に定義されているメソッドの動作を変更したい場合もあります。この場合、メソッド名を変えずにメソッドの機能をオーバーライド(再定義)するだけで済みます。次の例のようになります。
例
試してみる »
上記の例を実行したときの出力結果は次のとおりです:
Big box area is : 200
演算子のオーバーロード
私たちは、+ 演算子を使用して2つの Box オブジェクトのベクトル加算を実行し、* 演算子を使用して Box の width と height を乗算し、単項演算子 - を使用して Box の width と height の符号を反転したいと考えています。以下は、数学演算子の定義を備えた Box クラスのバージョンです:
オブジェクトの凍結
時には、オブジェクトが変更されるのを防ぎたいことがあります。Object の freeze メソッドはこれを実現し、オブジェクトを事実上定数にします。任意のオブジェクトは、freeze を呼び出すことでObject.freeze凍結できます。凍結されたオブジェクトは変更できません。つまり、そのインスタンス変数を変更することはできません。
あなたは、Object.frozen?メソッドを使用して、指定されたオブジェクトが既に凍結されているかどうかを確認できます。オブジェクトが凍結されている場合、そのメソッドは true を返し、そうでなければ false の値を返します。以下の例でこの概念を説明します。
例
試してみる »
上記のコードを実行すると、次の結果が生成されます:
Box object is frozen object
test.rb:20:in `setWidth=': can't modify frozen object (TypeError)
from test.rb:39
クラス定数
クラスの内部で定数を定義できます。これは、直接的な数値または文字列の値を変数に代入することで定義されます。定数の定義に @ や @@ を使う必要はありません。慣例により、定数の名前は大文字を使用します。
定数を定義すると、その値を変更することはできません。クラスの内部では、変数にアクセスするのと同じように定数に直接アクセスできます。ただし、クラスの外部から定数にアクセスしたい場合は、次を使用する必要がありますclassname::constant。以下の例のとおりです。
例
試してみる »
上記のコードを実行すると、次の結果が生成されます:
Area of the box is : 200 TATA Inc Box weight is: 10
クラス定数は継承でき、インスタンスメソッドと同様にオーバーライド(再定義)することもできます。
allocate を使用したオブジェクトの作成
オブジェクトコンストラクタを呼び出さないでinitializeオブジェクトを作成したい場合があります。つまり、new メソッドを使用してオブジェクトを作成する場合です。このような状況では、allocate を呼び出して未初期化のオブジェクトを作成できます。次の例のようになります。
例
試してみる »
上記のコードを実行すると、次の結果が生成されます:
Area of the box is : 200 test.rb:14: warning: instance variable @width not initialized test.rb:14: warning: instance variable @height not initialized test.rb:14:in `getArea': undefined method `*' for nil:NilClass (NoMethodError) from test.rb:29
クラス情報
Ruby の self と Java の this には類似点がありますが、大きく異なります。Java のメソッドはすべてインスタンスメソッド内で参照されるため、this は通常現在のオブジェクトを指します。一方、Ruby のコードは行ごとに実行されるため、異なるコンテキスト(context)では self の意味が異なります。次の例を見てみましょう。
例
試してみる »
上記のコードを実行すると、次の結果が生成されます:
Class of self = Class Name of self = Box
これは、クラス定義がそのクラスを現在のオブジェクトとして実行できることを意味し、また、メソッド定義の実行中にメタクラスと親クラスのそのメソッドが利用可能であることも意味します。
その他の拡張