Ruby-object-oriented

提供:Dev Guides
移動先:案内検索

Ruby-オブジェクト指向

Rubyは純粋なオブジェクト指向言語であり、Rubyにはすべてがオブジェクトとして見えます。 Rubyのすべての値はオブジェクトであり、文字列、数値、さらにはtrueとfalseでさえ、最も原始的なものですらあります。 クラス自体も、_Class_クラスのインスタンスである_object_です。 この章では、オブジェクト指向Rubyに関連するすべての主要な機能について説明します。

クラスはオブジェクトの形式を指定するために使用され、データ表現とそのデータを1つのきれいなパッケージに操作するためのメソッドを組み合わせます。 クラス内のデータとメソッドは、クラスのメンバーと呼ばれます。

Rubyクラス定義

クラスを定義するときには、データ型の設計図を定義します。 これは実際にはデータを定義しませんが、クラス名が何を意味するのか、つまりクラスのオブジェクトが何を構成するのか、そしてそのようなオブジェクトに対して実行できる操作は定義します。

クラス定義は、キーワード class で始まり、その後に class name が続き、 end で区切られます。 たとえば、次のようにキーワードクラスを使用してBoxクラスを定義しました-

class Box
   code
end

名前は大文字で開始する必要があり、慣例により、複数の単語を含む名前は、各単語を大文字で区切り文字なしで実行します(CamelCase)。

Rubyオブジェクトを定義する

クラスはオブジェクトの設計図を提供するため、基本的にオブジェクトはクラスから作成されます。 new キーワードを使用して、クラスのオブジェクトを宣言します。 次のステートメントは、クラスBoxの2つのオブジェクトを宣言します-

box1 = Box.new
box2 = Box.new

初期化メソッド

  • initializeメソッド*は標準のRubyクラスメソッドであり、 constructor が他のオブジェクト指向プログラミング言語で機能するのとほぼ同じように機能します。 initializeメソッドは、オブジェクトの作成時にいくつかのクラス変数を初期化する場合に役立ちます。 このメソッドは、パラメータのリストを取ることができ、他のルビーメソッドと同様に、以下に示すように def キーワードが先行します-
class Box
   def initialize(w,h)
      @width, @height = w, h
   end
end

インスタンス変数

インスタンス変数*はクラス属性の一種であり、クラスを使用してオブジェクトが作成されると、オブジェクトのプロパティになります。 すべてのオブジェクトの属性は個別に割り当てられ、他のオブジェクトと値を共有しません。 これらには@を使用してアクセスします。クラス内の演算子ですが、クラス外からアクセスするには、 accessorメソッド*と呼ばれる public メソッドを使用します。 上記で定義したクラス Box を使用する場合、@ widthと@ heightはクラスBoxのインスタンス変数です。

class Box
   def initialize(w,h)
      # assign instance variables
      @width, @height = w, h
   end
end

アクセサおよびセッターメソッド

クラスの外部から変数を使用可能にするには、変数を* accessorメソッド*内で定義する必要があります。これらのaccessorメソッドはgetterメソッドとも呼ばれます。 次の例は、アクセサメソッドの使用法を示しています-

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # accessor methods
   def printWidth
      @width
   end

   def printHeight
      @height
   end
end

# create an object
box = Box.new(10, 20)

# use accessor methods
x = box.printWidth()
y = box.printHeight()

puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"

上記のコードが実行されると、次の結果が生成されます-

Width of the box is : 10
Height of the box is : 20

変数の値にアクセスするために使用されるアクセサメソッドと同様に、Rubyは、以下のように定義される* setterメソッド*を使用して、クラスの外部からこれらの変数の値を設定する方法を提供します-

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   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 an object
box = Box.new(10, 20)

# use setter methods
box.setWidth = 30
box.setHeight = 50

# use accessor methods
x = box.getWidth()
y = box.getHeight()

puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"

上記のコードが実行されると、次の結果が生成されます-

Width of the box is : 30
Height of the box is : 50

インスタンスメソッド

インスタンスメソッド*も、 *def キーワードを使用して他のメソッドを定義するのと同じ方法で定義され、以下に示すようにクラスインスタンスを使用してのみ使用できます。 それらの機能は、インスタンス変数へのアクセスに限定されるものではありませんが、要件に応じてさらに多くのことができます。

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # instance method
   def getArea
      @width * @height
   end
end

# create an object
box = Box.new(10, 20)

# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"

上記のコードが実行されると、次の結果が生成されます-

Area of the box is : 200

クラスのメソッドと変数

  • クラス変数*は変数であり、クラスのすべてのインスタンス間で共有されます。 つまり、変数のインスタンスが1つあり、オブジェクトインスタンスによってアクセスされます。 クラス変数には、2つの@というプレフィックスが付きます。文字(@@)。 クラス変数は、以下に示すようにクラス定義内で初期化する必要があります。

クラスメソッドは、* def self.methodname()を使用して定義されます。これは、終了デリミタで終了し、次の例に示すようにクラス名を *classname.methodname として使用して呼び出されます-

#!/usr/bin/ruby -w

class Box
   # Initialize our class variables
   @@count = 0
   def initialize(w,h)
      # assign instance avriables
      @width, @height = w, h

      @@count += 1
   end

   def self.printCount()
      puts "Box count is : #@@count"
   end
end

# create two object
box1 = Box.new(10, 20)
box2 = Box.new(30, 100)

# call class method to print box count
Box.printCount()

上記のコードが実行されると、次の結果が生成されます-

Box count is : 2

to_sメソッド

定義するクラスには、オブジェクトの文字列表現を返す to_s インスタンスメソッドが必要です。 以下は、幅と高さの点でBoxオブジェクトを表すための簡単な例です-

#!/usr/bin/ruby -w

class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end
   # define to_s method
   def to_s
      "(w:#@width,h:#@height)"  # string formatting of the object.
   end
end

# create an object
box = Box.new(10, 20)

# to_s method will be called in reference of string automatically.
puts "String representation of box is : #{box}"

上記のコードが実行されると、次の結果が生成されます-

String representation of box is : (w:10,h:20)

アクセス制御

Rubyでは、インスタンスメソッドレベルで、 public、private、またはprotected の3つのレベルの保護が提供されます。 Rubyは、インスタンス変数とクラス変数にアクセス制御を適用しません。

  • パブリックメソッド-パブリックメソッドは誰でも呼び出すことができます。 メソッドは、常にプライベートである初期化を除き、デフォルトでパブリックです。
  • プライベートメソッド-プライベートメソッドにはアクセスできず、クラス外からも見ることができません。 クラスメソッドのみがプライベートメンバーにアクセスできます。
  • 保護されたメソッド-保護されたメソッドは、定義クラスとそのサブクラスのオブジェクトによってのみ呼び出すことができます。 アクセスは家族内で行われます。

以下は、3つのアクセス修飾子すべての構文を示す簡単な例です-

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      @width, @height = w, h
   end

   # instance method by default it is public
   def getArea
      getWidth() *getHeight
   end

   # define private accessor methods
   def getWidth
      @width
   end
   def getHeight
      @height
   end
   # make them private
   private :getWidth, :getHeight

   # instance method to print area
   def printArea
      @area = getWidth()* getHeight
      puts "Big box area is : #@area"
   end
   # make it protected
   protected :printArea
end

# create an object
box = Box.new(10, 20)

# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"

# try to call protected or methods
box.printArea()

上記のコードが実行されると、次の結果が生成されます。 ここでは、最初のメソッドは正常に呼び出されますが、2番目のメソッドには問題があります。

Area of the box is : 200
test.rb:42: protected method `printArea' called for #
<Box:0xb7f11280 @height = 20, @width = 10> (NoMethodError)

クラスの継承

オブジェクト指向プログラミングで最も重要な概念の1つは、継承の概念です。 継承を使用すると、クラスを別のクラスの観点から定義でき、アプリケーションの作成と保守が簡単になります。

継承は、コード機能と高速な実装時間を再利用する機会も提供しますが、残念ながら、Rubyは複数レベルの継承をサポートしませんが、Rubyは mixins をサポートします。 ミックスインは、インターフェイス部分のみが継承される多重継承の特殊な実装のようなものです。

クラスを作成するとき、プログラマは完全に新しいデータメンバーとメンバー関数を記述する代わりに、新しいクラスが既存のクラスのメンバーを継承するように指定できます。 この既存のクラスは、*ベースクラスまたはスーパークラス*と呼ばれ、新しいクラスは*派生クラスまたはサブクラス*と呼ばれます。

Rubyはサブクラス化、つまり継承の概念もサポートしており、次の例で概念を説明します。 クラスを拡張するための構文は簡単です。 クラス文字列に<文字とスーパークラスの名前を追加するだけです。 たとえば、次のクラス_BigBox_を_Box_のサブクラスとして定義します-

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      &commat;width, &commat;height = w, h
   end
   # instance method
   def getArea
      &commat;width *&commat;height
   end
end

# define a subclass
class BigBox < Box

   # add a new instance method
   def printArea
      &commat;area = &commat;width* &commat;height
      puts "Big box area is : #&commat;area"
   end
end

# create an object
box = BigBox.new(10, 20)

# print the area
box.printArea()

上記のコードが実行されると、次の結果が生成されます-

Big box area is : 200

メソッドのオーバーライド

派生クラスに新しい機能を追加することはできますが、親クラスで既に定義されているメソッドの動作を変更したい場合があります。 次の例に示すように、メソッド名を同じに保ち、メソッドの機能をオーバーライドするだけで簡単にできます-

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   def initialize(w,h)
      &commat;width, &commat;height = w, h
   end
   # instance method
   def getArea
      &commat;width *&commat;height
   end
end

# define a subclass
class BigBox < Box

   # change existing getArea method as follows
   def getArea
      &commat;area = &commat;width* &commat;height
      puts "Big box area is : #&commat;area"
   end
end

# create an object
box = BigBox.new(10, 20)

# print the area using overriden method.
box.getArea()

オペレータの過負荷

&plus;が欲しい&plus;を使用して2つのBoxオブジェクトのベクトル加算を実行する演算子、Boxの幅と高さをスカラーで乗算する*演算子、およびBoxの幅と高さを無効にする単項-演算子。 これは、数学演算子が定義されたBoxクラスのバージョンです-

class Box
   def initialize(w,h)     # Initialize the width and height
      &commat;width,&commat;height = w, h
   end

   def &plus;(other)       # Define &plus; to do vector addition
      Box.new(&commat;width &plus; other.width, &commat;height &plus; other.height)
   end

   def -&commat;           # Define unary minus to negate width and height
      Box.new(-&commat;width, -&commat;height)
   end

   def *(scalar)           # To perform scalar multiplication
      Box.new(&commat;width*scalar, &commat;height*scalar)
   end
end

オブジェクトの凍結

オブジェクトが変更されないようにしたい場合があります。 Objectのfreezeメソッドを使用すると、オブジェクトを定数に効果的に変換することができます。 Object.freeze を呼び出すと、すべてのオブジェクトを凍結できます。 凍結されたオブジェクトは変更できません。そのインスタンス変数は変更できません。

特定のオブジェクトが既に凍結されているかどうか、またはオブジェクトが凍結されている場合はtrueを返し、そうでない場合はfalseを返す* Object.frozen?*メソッドを使用してチェックできます。 次の例では、概念をクリアします-

#!/usr/bin/ruby -w

# define a class
class Box
   # constructor method
   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 an object
box = Box.new(10, 20)

# let us freez this object
box.freeze
if( box.frozen? )
   puts "Box object is frozen object"
else
   puts "Box object is normal object"
end

# now try using setter methods
box.setWidth = 30
box.setHeight = 50

# use accessor methods
x = box.getWidth()
y = box.getHeight()

puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"

上記のコードが実行されると、次の結果が生成されます-

Box object is frozen object
test.rb:20:in `setWidth=': can't modify frozen object (TypeError)
   from test.rb:39

クラス定数

クラス内で定数を定義するには、&commat;を使用せずに定義された変数に直接数値または文字列値を割り当てます。または&commat;&commat;。 慣例により、定数名は大文字のままにします。

定数が定義されると、その値を変更することはできませんが、変数のようにクラス内で定数に直接アクセスできますが、クラス外の定数にアクセスする場合は、 *classname
constant* を使用する必要があります以下の例に示します。
#!/usr/bin/ruby -w

# define a class
class Box
   BOX_COMPANY = "TATA Inc"
   BOXWEIGHT = 10
   # constructor method
   def initialize(w,h)
      &commat;width, &commat;height = w, h
   end
   # instance method
   def getArea
      &commat;width * &commat;height
   end
end

# create an object
box = Box.new(10, 20)

# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
puts Box::BOX_COMPANY
puts "Box weight is: #{Box::BOXWEIGHT}"

上記のコードが実行されると、次の結果が生成されます-

Area of the box is : 200
TATA Inc
Box weight is: 10

クラス定数は継承され、インスタンスメソッドのようにオーバーライドできます。

割り当てを使用してオブジェクトを作成

コンストラクター initialize を呼び出さずにオブジェクトを作成したい場合があります。 新しいメソッドを使用して、そのような場合は、_allocate_を呼び出すことができます。これにより、次の例のように初期化されていないオブジェクトが作成されます-

#!/usr/bin/ruby -w

# define a class
class Box
   attr_accessor :width, :height

   # constructor method
   def initialize(w,h)
      &commat;width, &commat;height = w, h
   end

   # instance method
   def getArea
      &commat;width * &commat;height
   end
end

# create an object using new
box1 = Box.new(10, 20)

# create another object using allocate
box2 = Box.allocate

# call instance method using box1
a = box1.getArea()
puts "Area of the box is : #{a}"

# call instance method using box2
a = box2.getArea()
puts "Area of the box is : #{a}"

上記のコードが実行されると、次の結果が生成されます-

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

クラス情報

クラス定義が実行可能なコードである場合、これはそれらが何らかのオブジェクトのコンテキストで実行されることを意味します:selfは何かを参照する必要があります。 それが何であるかを調べましょう。

#!/usr/bin/ruby -w

class Box
   # print class information
   puts "Type of self = #{self.type}"
   puts "Name of self = #{self.name}"
end

上記のコードが実行されると、次の結果が生成されます-

Type of self = Class
Name of self = Box

これは、そのクラスを現在のオブジェクトとしてクラス定義が実行されることを意味します。 これは、メソッド定義の実行中にメタクラスとそのスーパークラスのメソッドが利用できることを意味します。