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