学び直し Rubyがミニツク Part10

今日の教科書
[オブジェクトとは](http://www.minituku.net/courses/566428009/contents/372639456.html)

オブジェクト…インスタンスといい難しい概念。
色々な機能や変数を入れられる箱として認識していたけど。

#オブジェクトとは
一定領域を持つ仮想的な物体。

```
class Apple
  attr_accessor :color, :price
  def initialize(color="red", price=150)
    @color = color
    @price = price
  end
  def talking
    puts("りんごです")
  end
end
apple = Apple.new
apple.talking  #=> りんごです
```

#オブジェクト指向
 - カプセル化
 - ポリモルフィズム
 - ダックタイピング
 - アイデンティティ

わからん。

#カプセル化
データと手続きが一つになったオブジェクト。

```
class Foo
  def initialize(foo="foo", bar="bar")
    @foo = foo
    @bar = bar
  end
end
foo = Foo.new
foo.foo
NoMethodError: undefined method `foo' for #<Foo:0xb7c01cc0 @bar="bar", @foo="foo">
    from (irb):32
    from :0
```
クラス内のインスタンス変数の値を参照するメソッドを定義していない。Fooクラスに属しているが、インスタンス変数を見る手続きをしてないのでエラーが表示される。

```
class Foo
  attr_reader :foo, :bar
  def initialize(foo="foo", bar="bar")
    @foo = foo
    @bar = bar
  end
end
foo = Foo.new
p foo.foo  #=> foo
p foo.bar  #=> bar
```

アクセサメソッドを定義することで、オブジェクトの中身を取り出す。

```
class FamilyMember
  def initialize(family_name="Yamada", name="Tarou")
    @family_name = family_name
    @name = name
  end
  def name
    return @family_name + " " + @name
  end
end
member = FamilyMember.new
p member.name  #=> Yamada Tarou
```

オブジェクトにメッセージを送った際の振舞いの隠蔽。
名前を返すようにメソッドを呼び出し。オブジェクト自身は名前をどのように持っていたか知らなくても使える。
メソッドが継承によって実装されているメソッドなのかわからなくても、メソッドは使える。

```
class Foo
  def foo
    puts("foo")
  end
end
class Bar < Foo
end
bar = Bar.new
bar.foo  #=> foo
```

#ポリモルフィズム
オブジェクトにメッセージを送って、手続きがあればメッセージに対する処理を実行する。
このメッセージに対する手続きは違うオブジェクトに対しても、同じメッセージを送っても似たような動きをしてくれる可能性がある。それをポリモルフィズムという。

```
p "abc".length      #=> 3
p [1, 2, 3].length  #=> 3
p {:foo => 1, :bar => 2, :baz => 3}.length  #=> 3
```

##ダックタイピング
オブジェクトがどのクラスに所属しているかで考えるのではなく、オブジェクトがどのようなメソッドを知っているかで考えること。

```
def print_length(obj)
  puts("obj length is #{obj.length}")
end
```

メソッドの引数に渡されるオブジェクトがlengthを知っていると処理が実行される。
この処理が異なるオブジェクトであっても動作するなら、問題ないという考え方。

##アイデンティティ

 > 異なる変数が指し示すオブジェクトはどのくらい同じなのでしょうか。あるオブジェクトの値と別のオブジェクトの値が同じなのかは演算子で判定することができます。メソッドは各オブジェクトごとに、適切に定義されなければいけません。なぜなら各オブジェクトごとに何を比べて同じと判定するかは違うからです。

```
a = "foo"
b = a
# 同じ文字かで判定する
p(a == b)  #=> true
c = [1, 2]
d = c
# 配列の要素が同じかで判定する
p(c == d)  #=> true
e = 1
f = "1"
# 異なるオブジェクトで判定する
p(e == f)  #=> false
```

###object_idメソッド

 > 各オブジェクトごとに持っている一意な整数を返します。オブジェクトに対してどのような整数が割り当てられるかは不定です。

```
a = "foo"
b = "bar"
# どのような整数が割り当てられているかはわからない
p(a.object_id)
p(b.object_id)
```

###eql?メソッド

 > eql?メソッドでふたつのオブジェクトを比較すると、オブジェクトの値が同じならtrueを返します。オブジェクトの値が違う時はfalseを返します。

```
a = "foo"
b = "foo"
p(a.eql?(b))  #=> true
a = "foo"
b = "bar"
p(a.eql?(b))  #=> false
```

###equal?メソッド

 > equal?メソッドでふたつのオブジェクトを比較すると、オブジェクトが同じならtrueを返します。オブジェクトが違う時はfalseを返します。

```
a = "foo"
b = "bar"
p(a.equal?(b))  #=> false
a = "foo"
a = b
p(a.equal?(b))  #=> true
```

 > これらのオブジェクトを判定するメソッドには違いがあります。オブジェクトの値が同じであってもオブジェクトそのものが同じであるかはわかりません。ふたつのオブジェクトが同一であるかを判定するにはequal?というメソッドを使います。equal?メソッドはそれぞれのオブジェクトが持つ固有の値であるIDを比較して判定します。このIDはobject_idメソッドで調べることができます

```
a = "foo"
b = "foo"
p(a == b)       #=> 値が同じなのでtrue
p(a.equal?(b))  #=> 値が違うのでfalse
a = b
p(a.equal?(b))  #=> 同一なのでtrue
```

#まとめ

 > ・オブジェクトとは
オブジェクトは仮想的に作られた「もの」であり、現実にある物体とは違います。
・カプセル化
オブジェクトの中にある情報を知るには、オブジェクトが手続きを知っていないと調べられないという考え方です。
・ポリモルフィズム
異なるオブジェクトに同じ手続きを使ったとしても、その手続きが期待したとおりの動きをしてくれることです。
・ダックタイピング
どのようなクラスにオブジェクトが属しているかで考えるのではなく、オブジェクトの手続きを中心にして考えることです。
・アイデンティティ
直訳すると「自己同一性」です。オブジェクトが識別できるかということです。
・同値性
オブジェクトの値が同じならば真を返します。==メソッドやeql?メソッドを使うことによって、調べることができます。
・同一性
オブジェクトが同じならば真を返します。equal?メソッドを使うことによって、調べることができます。