Rubyオブジェクト指向の知識まとめ
Rubyは純粋にオブジェクト指向の言語です。Rubyに含まれるすべてのものはオブジェクトであり、Rubyのすべての値はオブジェクトです。最も原始的なものでさえ、文字列、数値、trueとfalseさえオブジェクトなのです。クラスはそれ自体がオブジェクトであり、Class クラスのインスタンスである。この章では、Rubyのオブジェクト指向に関連するすべての主要な機能を説明します。
クラスは、データ表現とメソッドを組み合わせたオブジェクトの形を指定し、データをきちんとパッケージ化して整理するために使われます。クラス内のデータやメソッドは、クラスのメンバと呼ばれます。
Rubyのクラス定義
クラスを定義するとき、実際にはデータ型の青写真を定義していることになります。これは実際にはデータを定義するのではなく、クラスの名前が意味するもの、つまり、そのクラスのオブジェクトが何から構成され、そのオブジェクトに対してどのような操作が可能かを定義しているのです。
クラス定義は、キーワードclassで始まり、クラス名が続き、endで終わります。例えば、キーワードclassを使ってBoxクラスを定義すると、次のようになります。
class Box
code
end
慣習上、名前は大文字で始まり、複数の単語を含む場合はそれぞれの単語が大文字になりますが、単語の間に区切りはありません(例:CamelCase)。
Rubyオブジェクトの定義
クラスはオブジェクトの設計図を提供するので、基本的にオブジェクトはクラスを元に作成されます。クラスのオブジェクトを宣言するにはnewキーワードを使用します。次の文は、クラスBoxの2つのオブジェクトを宣言しています。
box1 = Box.new
box2 = Box.new
初期化メソッド
initialize メソッドは Ruby の標準的なクラスメソッドで、他のオブジェクト指向プログラミング言語におけるコンストラクタの動作に似ています。initialize メソッドは、オブジェクトを作成する際にクラス変数を初期化したい場合に便利です。このメソッドは一連の引数を取り、他の Ruby メソッドと同様に、以下のように def キーワードを前に置く必要があります。
class Box
def initialize(w,h)
@width, @height = w, h
end
end
インスタンス変数
インスタンス変数はクラスの属性で、そのクラスを使ってオブジェクトを作成すると、そのオブジェクトのプロパティになります。各オブジェクトのプロパティは個別に割り当てられ、他のオブジェクトと値を共有することはありません。クラス内部では、これらのプロパティに@演算子でアクセスし、クラス外部では、アクセッサメソッドと呼ばれるパブリックメソッドでアクセスします。上で定義したクラスBoxを例に、@widthと@heightをクラスBoxのインスタンス変数として使ってみましょう。
class Box
def initialize(w,h)
# Assign values to the instance variables
@width, @height = w, h
end
end
アクセサ(ゲッター) & セッターメソッド
クラス内で定義された変数をクラス外から読み出すには、アクセッサ(ゲッター)メソッドを定義することでアクセスできます。次の例は、アクセッサメソッドの使い方を示しています。 <未定義
#! /usr/bin/ruby -w
# Define the class
class Box
# Constructor
def initialize(w,h)
@width, @height = w, h
end
# Accessor methods
def printWidth
@width
end
def printHeight
@height
end
end
# Create an object to initialize the height and width of the box
box = Box.new(10, 20)
# Use the accessor method
x = box.printWidth()
y = box.printHeight()
puts "boxWidth : #{x}"
puts "boxHeight : #{y}"
上記のコードを実行すると、以下のような結果が得られます。
ボックスの幅:10
ボックスの高さ:20
変数の値にアクセスするためのアクセサメソッドと同様に、Rubyには、クラス内ですでに定義されている変数にクラス外の引数を渡す方法があり、次のように定義されるセッターメソッドと呼ばれます。
#! /usr/bin/ruby -w
# Define the class
class Box
# Constructor methods
def initialize(w,h)
@width, @height = w, h
end
# Accessor methods
def getWidth
@width
end
def getHeight
@height
end
# Setter methods
def setWidth=(value)
@width = value
end
def setHeight=(value)
@height = value
end
end
# Create the object
box = Box.new(10, 20)
# Use the setter method
box.setWidth = 30
box.setHeight = 50
# Use the accessor method
x = box.getWidth()
y = box.getHeight()
puts "boxWidth : #{x}"
puts "boxHeight : #{y}"
上記のコードを実行すると、以下のような結果が得られます。
ボックスの幅:30
ボックスの高さ:50
この2つのメソッドは非常によく使われるので、Rubyでは3つの属性宣言メソッド attr_accessor :変数名, attr_reader :変数名, attr_writer :変数名を定義しています。ここで: accessor=reader+writer となります。
また、変数名の前には : が必要で、変数名は , で区切られることに注意してください。
インスタンスメソッド
インスタンスメソッドは、他のメソッドと同様にdefキーワードで定義しますが、以下の例に示すように、クラスインスタンスを通してのみ使用することができます。その機能はインスタンス変数へのアクセスにとどまらず、必要な限りのタスクを実行することができます。
#! /usr/bin/ruby -w
# Define the class
class Box
# Construct method
def initialize(w,h)
@width, @height = w, h
end
# Instance methods
def getArea
@width * @height
end
end
# Create the object
box = Box.new(10, 20)
# Call the instance method
a = box.getArea()
puts "Area of the box is : #{a}"
上記のコードを実行すると、以下のような結果が得られます。
ボックスの面積:200
クラスメソッドとクラス変数
クラス変数とは、クラスの全インスタンスで共有される変数です。言い換えれば、クラス変数のインスタンスは、オブジェクトのすべてのインスタンスからアクセスすることができます。クラス変数の先頭には2つの @ 文字 (@@) が付き、次の例に示すように、クラス変数はクラス定義の中で初期化する必要があります。
クラスメソッドはdef self.methodname()で定義し、クラスメソッドはend separatorで終了させる。クラスメソッドは、次の例のようにクラス名と一緒にclassname.methodname形式で呼び出すことができます。
#! /usr/bin/ruby -w
class Box
# Initialize class variables
@@count = 0
def initialize(w,h)
# Assign values to instance variables
@width, @height = w, h
@@count += 1
end
def self.printCount()
puts "Box count is : #@@count"
end
end
# Create two objects
box1 = Box.new(10, 20)
box2 = Box.new(30, 100)
# Call the class method to output the box count
Box.printCount()
上記のコードを実行すると、以下のような結果が得られます。
ボックス数:2
to_sメソッド
定義したどのクラスも、オブジェクトの文字列表現を返すto_sインスタンスメソッドを持っています。ここでは、Boxオブジェクトを幅と高さに基づいて表現する簡単な例を示します。
#! /usr/bin/ruby -w
class Box
# Constructor methods
def initialize(w,h)
@width, @height = w, h
end
# Define the to_s method
def to_s
"(w:#@width,h:#@height)" # String format of the object
end
end
# Create the object
box = Box.new(10, 20)
# Automatically call the to_s method
puts "String representation of box is : #{box}"
上記のコードを実行すると、以下のような結果が得られます。
ボックスの文字列表現は: (w:10,h:20)です。
アクセス制御
Rubyでは、インスタンスメソッドの保護はpublic, private, protectedの3段階があり、インスタンス変数やクラス変数にはアクセス制御はかかりません。
- パブリック・メソッド。パブリックメソッドは、どのようなオブジェクトからも呼び出すことができます。デフォルトでは、メソッドはすべてパブリックですが、initialize メソッドは常にプライベートです。
- プライベートメソッド。プライベートメソッドは、クラスの外からアクセスしたり、見ることができません。クラスメソッドのみがプライベートメンバーにアクセスすることができます。
-
プロテクトされたメソッド。保護されたメソッドは、クラスとそのサブクラスのオブジェクトによってのみ呼び出すことができます。また、アクセスはクラスとそのサブクラス内でのみ可能です。
以下は、これら3つの修飾子の構文を示す簡単な例です。
#! /usr/bin/ruby -w
# Define the class
class Box
# Constructor methods
def initialize(w,h)
@width, @height = w, h
end
# Instance methods are public by default
def getArea
getWidth() * getHeight
end
# Define the private accessor methods
def getWidth
@width
end
def getHeight
@height
end
# make them private
private :getWidth, :getHeight
# Example methods for outputting area
def printArea
@area = getWidth() * getHeight
puts "Big box area is : #@area"
end
# Let the instance method be protected
protected :printArea
end
# Create the object
box = Box.new(10, 20)
# Call the instance method
a = box.getArea()
puts "Area of the box is : #{a}"
# Try to call the protected instance method
box.printArea()
上記のコードを実行すると、以下のような結果になります。ここでは、1つ目のメソッドは正常に呼び出されますが、2つ目のメソッドで問題が発生します。
ボックスの面積:200
test.rb:42: protected method `printArea' called for #.
<Box:0xb7f11280 @height=20, @width=10> (NoMethodError)です。
クラスの継承
オブジェクト指向プログラミングにおいて、継承は最も重要な概念の一つである。継承によって、他のクラスをベースにしてクラスを定義できるようになり、アプリケーションの作成と保守が容易になります。
Rubyは多重継承をサポートしていませんが、ミキシンをサポートしています。ミキシンは多重継承の特定の実装のようなもので、インタフェース部分のみを継承することができます。
クラスを作成する際、プログラマーは新しいクラスが既存のクラスのメンバーを継承することを直接指定できるので、新しいデータメンバーやメンバー関数をゼロから書く必要はありません。この既存のクラスを基底クラスまたは親クラスと呼び、新しいクラスを派生クラスまたは子クラスと呼びます。
Ruby にはサブクラス化、すなわち継承の概念もあり、以下の例で説明します。クラスを拡張するための構文は非常に簡単です。class文に<文字と親クラスの名前を加えるだけです。たとえば、BoxのサブクラスとしてBigBoxというクラスを定義するのは次のとおりです。
#! /usr/bin/ruby -w
# Define the class
class Box
# Constructor methods
def initialize(w,h)
@width, @height = w, h
end
# Instance methods
def getArea
@width * @height
end
end
# Define subclasses
class BigBox < Box
# Add a new instance method
def printArea
@area = @width * @height
puts "Big box area is : #@area"
end
end
# Create the object
box = BigBox.new(10, 20)
# Output area
box.printArea()
上記のコードを実行すると、以下のような結果が得られます。
ビッグボックスの面積は:200
メソッドのオーバーロード
派生クラスには新しい機能を追加できますが、時には親クラスで既に定義されているメソッドの動作を変更したい場合があります。この場合、次の例に示すように、メソッド名を変更せずに、単純にメソッドの機能をオーバーロードすることができます。
#! /usr/bin/ruby -w
# Define the class
class Box
# Constructor methods
def initialize(w,h)
@width, @height = w, h
end
# Instance methods
def getArea
@width * @height
end
end
# Define subclasses
class BigBox < Box
# Change the existing getArea method
def getArea
@area = @width * @height
puts "Big box area is : #@area"
end
end
# Create object
box = BigBox.new(10, 20)
# Output area using the overloaded method
box.getArea()
上記の実行例の出力は
ビッグボックスの面積は:200
演算子のオーバーロード
2 つの Box オブジェクトのベクトル加算を行う + 演算子、Box の幅と高さを乗算する * 演算子、Box の幅と高さを反転する単項演算子 - を使用したいと思います。以下は、Box クラスに数学演算子を定義したバージョンです。
class Box
def initialize(w,h) # Initialize width and height
@width,@height = w, h
end
def +(other) # Define + to perform vector addition
Box.new(@width + other.width, @height + other.height)
end
def -@ # Define the unary operator - to invert width and height
Box.new(-@width, -@height)
end
def *(scalar) # Perform scalar multiplication
Box.new(@width*scalar, @height*scalar)
end
end
オブジェクトの凍結
時には、オブジェクトが変更されるのを防ぎたいことがあります。Objectでは、freezeメソッドがこれを実現し、オブジェクトを効果的に定数に変えます。Object.freezeを呼び出すことで、どんなオブジェクトでもフリーズさせることができます。フリーズしたオブジェクトは変更することができません。つまり、そのインスタンス変数を変更することはできません。
Object.frozen? メソッドを使用すると、指定したオブジェクトがフリーズしているかどうかを確認できます。このメソッドは、オブジェクトがフリーズしている場合は true を返し、そうでない場合は false を返します。次の例でこの概念を説明します。
#! /usr/bin/ruby -w
# Define the class
class Box
# Constructor methods
def initialize(w,h)
@width, @height = w, h
end
# Accessor methods
def getWidth
@width
end
def getHeight
@height
end
# Setter methods
def setWidth=(value)
@width = value
end
def setHeight=(value)
@height = value
end
end
# Create the object
box = Box.new(10, 20)
# Let's freeze the object
box.freeze
if( box.frozen? )
puts "Box object is frozen object"
else
puts "Box object is normal object"
end
# Now try using the setter method
box.setWidth = 30
box.setHeight = 50
# Use the accessor method
x = box.getWidth()
y = box.getHeight()
puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"
上記のコードを実行すると、以下のような結果が得られます。
Boxオブジェクトはフリーズしたオブジェクト
test.rb:20:in `setWidth=': フリーズしたオブジェクトを変更できない (TypeError)
test.rb:39より
クラス定数
クラス内部で定数を定義するには、変数に直接数値または文字列を代入します。定数は @ や @@ を使用せずに定義します。慣習として、定数名は大文字で表記されます。
定数は一度定義すると、その値を変更することはできません。定数には、変数と同じようにクラスの内部から直接アクセスできますが、クラスの外部から定数にアクセスする場合は、次の例のようにclassname::constantを使用しなければなりません。
#! /usr/bin/ruby -w
# Define the class
class Box
BOX_COMPANY = "TATA Inc"
BOXWEIGHT = 10
# Constructor methods
def initialize(w,h)
@width, @height = w, h
end
# Instance methods
def getArea
@width * @height
end
end
# Create the object
box = Box.new(10, 20)
# Call the instance method
a = box.getArea()
puts "Area of the box is : #{a}"
puts Box::BOX_COMPANY
puts "Box weight is: #{Box::BOXWEIGHT}"
上記のコードを実行すると、以下のような結果が得られます。
ボックスの面積:200
株式会社タタ
箱の重量は 10
クラス定数はインスタンスメソッドと同様に継承、オーバーロードが可能です。
allocateを使ったオブジェクトの作成
オブジェクトのコンストラクタinitializeを呼ばずに、つまりnewメソッドを使ってオブジェクトを作成したい場合があります。その場合は、次の例のようにallocateを呼んで、初期化されていないオブジェクトを作成することが可能です。
#! /usr/bin/ruby -w
# Define the class
class Box
attr_accessor :width, :height
# Constructor methods
def initialize(w,h)
@width, @height = w, h
end
# Instance methods
def getArea
@width * @height
end
end
# Create an object using new
box1 = Box.new(10, 20)
# Use allocate to create another object
box2 = Box.allocate
# Use box1 to call the instance method
a = box1.getArea()
puts "Area of the box is : #{a}"
# Use box2 to call the instance method
a = box2.getArea()
puts "Area of the box is : #{a}"
上記のコードを実行すると、以下のような結果が得られます。
ボックスの面積:200
test.rb:14: 警告: インスタンス変数 @width が初期化されていません。
test.rb:14: 警告: インスタンス変数 @height が初期化されていません。
test.rb:14:in `getArea': 未定義のメソッド `*' です。
for nil:NilClass (NoMethodError) from test.rb:29
クラス情報
Rubyのselfは、Javaのthisと似ていますが、大きく異なります。Javaのメソッドはインスタンスメソッドで参照されるので、これは一般に現在のオブジェクトを指します。Rubyのコードは一行ずつ実行されるので、selfは文脈によって異なる意味を持つ。次の例を見てみましょう: .
#! /usr/bin/ruby -w
class Box
# Output class information
puts "Class of self = #{self.class}"
puts "Name of self = #{self.name}"
end
上記のコードを実行すると、以下のような結果が得られます。
自己のクラス = クラス
自己の名前 = Box
これは、クラスをカレント・オブジェクトとみなしてクラス定義を実行できることを意味し、また、メソッド定義の実行期間中はメタクラスと親クラスでメソッドが利用可能であることを意味します。
以上、Rubyのオブジェクト指向の知識をまとめてみました。Rubyのオブジェクト指向の知識については、Scripting Houseの他の関連記事も参考にしてみてください
関連
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン