コードは次のとおりです。
class Person
def initialize(age)
@age = age
end
def age
@age
end
def age_difference_with(other_person)
(self.age - other_person.age).abs
end
protected :age
end
私が知りたいのは、@age
メソッドでself.age
とage_difference_with
を使用することの違いです。
@age
と記述すると、インスタンス変数@age
に直接アクセスします。 self.age
を書き込むと、オブジェクトにメッセージage
を送信するように指示します。これは通常、インスタンス変数@age
を返しますが、age
メソッドは特定のサブクラスに実装されます。たとえば、実際よりも常に10歳若い年齢を常に報告するMiddleAgedSocialiteクラスがあるとします。または、より現実的には、PersistentPersonクラスは永続ストアからそのデータを遅延的に読み取り、その永続データをすべてハッシュにキャッシュします。
違いは、メソッドの使用を実装から分離していることです。プロパティの実装が変更された場合(生年月日を保持し、現在と生年月日の時間差に基づいて年齢を計算するなど)、メソッドに依存するコードを変更する必要はありません。プロパティを直接使用した場合、変更はコードの他の領域に伝播する必要があります。この意味で、プロパティを直接使用することは、クラスが提供するインターフェイスを使用するよりも脆弱です。
Struct.new
からクラスを継承する場合は注意が必要です。これは、初期化子を生成する適切な方法です( Rubyで初期化子を生成する方法 )
class Node < Struct.new(:value)
def initialize(value)
@value = value
end
def show()
p @value
p self.value # or `p value`
end
end
n = Node.new(30)
n.show()
戻ります
30
nil
ただし、初期化子を削除すると、戻ります
nil
30
クラス定義付き
class Node2
attr_accessor :value
def initialize(value)
@value = value
end
def show()
p @value
p self.value
end
end
コンストラクターを提供する必要があります。
n2 = Node2.new(30)
n2.show()
戻ります
30
30
違いはありません。私は、それがself.age
およびother_person.age
互いに近い。
Useを使用すると、実際のゲッターを将来記述することができ、インスタンス変数を返すだけでなく、メソッドを変更する必要がなくなるだけでなく、より複雑な処理を行うことができると思います。
しかし、それは、オブジェクトの実装が変更された場合、他のメソッドを変更するのが合理的であるため、心配することはありそうもない抽象化です。ある時点で、オブジェクト自体内の単純な参照は完全に合理的です。
いずれにしても、age
プロパティの抽象化では、self
の明示的な使用については説明されていません。プレーンなage
もアクセサーを呼び出したためです。
最初の答えは完全に正しいですが、相対的な初心者として、それが何を暗示しているのかすぐにはわかりませんでした(メッセージを自己に送信しますか?ええと...)。短い例が役立つと思います:
class CrazyAccessors
def bar=(val)
@bar = val - 20 # sets @bar to (input - 20)
end
def bar
@bar
end
def baz=(value)
self.bar = value # goes through `bar=` method, so @bar = (50 - 20)
end
def quux=(value)
@bar = value # sets @bar directly to 50
end
end
obj = CrazyAccessors.new
obj.baz = 50
obj.bar # => 30
obj.quux = 50
obj.bar # => 50