Rubyのオブジェクト指向


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

クラスは、データ表現とメソッドを組み合わせてデータをきちんとしたパッケージに編成するオブジェクトの形式を指定するために使用されます。クラス内のデータとメソッドは、クラスのメンバーと呼ばれます。

Ruby クラス定義

クラスを定義すると、実際にはデータ型のブループリントを定義することになります。これは実際にはデータを定義するのではなく、クラスの名前が何を意味するか、つまりクラスのオブジェクトが何で構成され、そのオブジェクトに対してどのような操作を実行できるかを定義します。

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

class Box
   code
end

慣例により、名前は大文字で始める必要があります。複数の単語が含まれる場合、各単語の最初の文字は大文字になります。ここに区切り文字を入れます (例: CamelCase)。

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

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

box1 = Box.new
box2 = Box.new

initialize メソッド

initialize メソッドは標準の Ruby クラス メソッドであり、クラスのコンストラクターであり、他のオブジェクト指向プログラミングの constructor と同じように機能します。似たような言語。 initialize メソッドは、オブジェクトの作成中にいくつかのクラス変数を初期化する場合に便利です。このメソッドは一連のパラメータを受け取り、他の Ruby メソッドと同様に、このメソッドを使用するときは、以下に示すように def キーワードを前に置く必要があります:

class Box
   def initialize(w,h)
      @width, @height = w, h
   end
end

インスタンス変数

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

class Box
   def initialize(w,h)
      # 给实例变量赋值
      @width, @height = w, h
   end
end

Accessor メソッドと Setter メソッド

クラスの外で変数を使用するには、accessor メソッド 内でこれらの変数を定義する必要があります。accessor は実際には getter と同等です。次の例は、アクセサー メソッドの使用法を示しています。

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造函数
   def initialize(w,h)
      @width, @height = w, h
   end

   # 访问器方法
   def printWidth
      @width
   end

   def printHeight
      @height
   end
end

# 创建对象
box = Box.new(10, 20)

# 使用访问器方法
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

# 定义类
class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end

   # 访问器方法
   def getWidth
      @width
   end
   def getHeight
      @height
   end

   # 设置器方法
   def setWidth=(value)
      @width = value
   end
   def setHeight=(value)
      @height = value
   end
end

# 创建对象
box = Box.new(10, 20)

# 使用设置器方法
box.setWidth = 30
box.setHeight = 50

# 使用访问器方法
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

# 定义类
class Box
   # 构造方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 实例方法
   def getArea
      @width * @height
   end
end

# 创建对象
box = Box.new(10, 20)

# 调用实例方法
a = box.getArea()
puts "Area of the box is : #{a}"


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

Area of the box is : 200

クラスメソッドとクラス変数

クラス変数 は、クラスのすべてのインスタンス間で共有される変数です。つまり、クラス変数のインスタンスには、すべてのオブジェクト インスタンスからアクセスできます。次の例に示すように、クラス変数には 2 つの @ 文字 (@@) が接頭辞として付けられ、クラス定義で初期化する必要があります。

クラスメソッドは、def self.methodname()を使用して定義されます。クラスメソッドは終了区切り文字で終わります。クラス メソッドは、次の例に示すように、クラス名を指定した形式 classname.methodname を使用して呼び出すことができます。

#!/usr/bin/ruby -w

class Box
   # 初始化类变量
   @@count = 0
   def initialize(w,h)
      # 给实例变量赋值
      @width, @height = w, h

      @@count += 1
   end

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

# 创建两个对象
box1 = Box.new(10, 20)
box2 = Box.new(30, 100)

# 调用类方法来输出盒子计数
Box.printCount()


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

Box count is : 2

to_s メソッド

you 定義されたクラスには、オブジェクトの文字列表現を返す to_s インスタンス メソッドがあります。幅と高さの観点から Box オブジェクトを表す簡単な例を次に示します:

#!/usr/bin/ruby -w

class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 定义 to_s 方法
   def to_s
      "(w:#@width,h:#@height)"  # 对象的字符串格式
   end
end

# 创建对象
box = Box.new(10, 20)

# 自动调用 to_s 方法
puts "String representation of box is : #{box}"


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

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

アクセス制御

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

  • パブリック メソッド: パブリック メソッドは任意のオブジェクトから呼び出すことができます。デフォルトでは、常にプライベートである初期化メソッドを除いて、メソッドはすべてパブリックです。

  • プライベート メソッド: プライベート メソッドはクラスの外部からアクセスしたり表示したりすることはできません。クラスメソッドのみがプライベートメンバーにアクセスできます。

  • 保護されたメソッド: 保護されたメソッドは、クラスとそのサブクラスのオブジェクトによってのみ呼び出すことができます。また、アクセスはクラスとそのサブクラス内でのみ可能です。

これら 3 つの修飾子の構文を示す簡単な例を次に示します。

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end

   # 实例方法默认是 public 的
   def getArea
      getWidth() * getHeight
   end

   # 定义 private 的访问器方法
   def getWidth
      @width
   end
   def getHeight
      @height
   end
   # make them private
   private :getWidth, :getHeight

   # 用于输出面积的实例方法
   def printArea
      @area = getWidth() * getHeight
      puts "Big box area is : #@area"
   end
   # 让实例方法是 protected 的
   protected :printArea
end

# 创建对象
box = Box.new(10, 20)

# 调用实例方法
a = box.getArea()
puts "Area of the box is : #{a}"

# 尝试调用 protected 的实例方法
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 は、継承であるサブクラス化の概念も提供します。次の例でこの概念を説明します。クラスを拡張するための構文は非常に簡単です。 < 文字と親クラスの名前を class ステートメントに追加するだけです。たとえば、クラス BigBox は、Box のサブクラスとして以下で定義されています。

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 实例方法
   def getArea
      @width * @height
   end
end

# 定义子类
class BigBox < Box

   # 添加一个新的实例方法
   def printArea
      @area = @width * @height
      puts "Big box area is : #@area"
   end
end

# 创建对象
box = BigBox.new(10, 20)

# 输出面积
box.printArea()


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

Big box area is : 200

メソッドのオーバーロード

これを行うことができます派生クラスで新しい機能を追加しますが、親クラスですでに定義されているメソッドの動作を変更したい場合もあります。このとき、次の例に示すように、メソッド名を変更せずにメソッドの関数をオーバーロードできます。

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 实例方法
   def getArea
      @width * @height
   end
end

# 定义子类
class BigBox < Box

   # 改变已有的 getArea 方法
   def getArea
      @area = @width * @height
      puts "Big box area is : #@area"
   end
end

# 创建对象
box = BigBox.new(10, 20)

# 使用重载的方法输出面积
box.getArea()


上記の例の出力結果は次のとおりです。

Big box area is : 200

Operator overloading

+ 演算子を使用するには * 演算子を使用してボックスの幅と高さを乗算し、単項演算子 - を使用してボックスの幅と高さを否定し、2 つの Box オブジェクトのベクトル加算を実行します。以下は、算術演算子定義を含む Box クラスのバージョンです:

class Box
  def initialize(w,h) # 初始化 width 和 height
    @width,@height = w, h
  end

  def +(other)         # 定义 + 来执行向量加法
    Box.new(@width + other.width, @height + other.height)
  end

  def -@               # 定义一元运算符 - 来对 width 和 height 求反
    Box.new(-@width, -@height)
  end

  def *(scalar)        # 执行标量乘法
    Box.new(@width*scalar, @height*scalar)
  end
end

オブジェクトの凍結

場合によっては、オブジェクトが変更されるのを防ぎたいことがあります。 Object では、これはオブジェクトを効果的に定数に変えるフリーズ メソッドで実現されます。 Object.freezeを呼び出すことで、任意のオブジェクトを凍結できます。凍結されたオブジェクトは変更できません。つまり、そのインスタンス変数を変更することはできません。

Object.frozen? メソッドを使用して、特定のオブジェクトが凍結されているかどうかを確認できます。このメソッドは、オブジェクトが凍結されている場合は true を返し、それ以外の場合は false 値を返します。次の例は、この概念を説明しています:

#!/usr/bin/ruby -w

# 定义类
class Box
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end

   # 访问器方法
   def getWidth
      @width
   end
   def getHeight
      @height
   end

   # 设置器方法
   def setWidth=(value)
      @width = value
   end
   def setHeight=(value)
      @height = value
   end
end

# 创建对象
box = Box.new(10, 20)

# 让我们冻结该对象
box.freeze
if( box.frozen? )
   puts "Box object is frozen object"
else
   puts "Box object is normal object"
end

# 现在尝试使用设置器方法
box.setWidth = 30
box.setHeight = 50

# 使用访问器方法
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

クラス定数

直接数値または文字列を渡すことによって、クラス内で定数を定義できます。 value を変数に代入して定義する場合、定数の定義には @ または @@ を使用する必要はありません。慣例により、定数名は大文字で表記されます。

定数が定義されると、その値を変更することはできません。変数にアクセスするのと同じように、クラス内で定数に直接アクセスできますが、クラス外の定数にアクセスしたい場合は、classname :: を使用する必要があります。以下の例に示すように、定数

#!/usr/bin/ruby -w

# 定义类
class Box
   BOX_COMPANY = "TATA Inc"
   BOXWEIGHT = 10
   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end
   # 实例方法
   def getArea
      @width * @height
   end
end

# 创建对象
box = Box.new(10, 20)

# 调用实例方法
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

クラス定数は、インスタンス メソッドと同様に継承またはオーバーロードできます。

allocate を使用してオブジェクトを作成する

オブジェクト コンストラクター initialize を呼び出さずにオブジェクトを作成したい状況があるかもしれません。つまり、 new メソッドを使用してオブジェクトを作成します。この場合、次のように、allocate を呼び出して初期化されていないオブジェクトを作成できます。次の例に示されています:

#!/usr/bin/ruby -w

# 定义类
class Box
   attr_accessor :width, :height

   # 构造器方法
   def initialize(w,h)
      @width, @height = w, h
   end

   # 实例方法
   def getArea
      @width * @height
   end
end

# 使用 new 创建对象
box1 = Box.new(10, 20)

# 使用 allocate 创建两一个对象
box2 = Box.allocate

# 使用 box1 调用实例方法
a = box1.getArea()
puts "Area of the box is : #{a}"

# 使用 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

クラス情報

Ruby の self と Java の this には類似点がありますが、大きく異なるものでもあります。 Java メソッドはインスタンス メソッドで参照されるため、通常、これは現在のオブジェクトを指します。 Ruby のコードは 1 行ずつ実行されるため、self はコンテキストごとに異なる意味を持ちます。次のインスタンスを見てみましょう: .

#!/usr/bin/ruby -w

class Box
   # 输出类信息
   puts "Class of self = #{self.class}"
   puts "Name of self = #{self.name}"
end


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

Class of self = Class
Name of self = Box

これは、クラスを現在のオブジェクトにすることでクラス定義を実行できることを意味します。また、メソッド定義の実行中にメタクラスと親クラスのメソッドが使用可能であることを意味します。