Bây giờ hãy tạo một đối tượng greeter và sử dụng nó:

<figure class="highlight"><pre><code class="language-irb" data-lang="irb"><span class="gp">irb(main):035:0&gt;</span><span class="w"> </span><span class="n">greeter</span> <span class="o">=</span> <span class="no">Greeter</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s2">"Pat"</span><span class="p">)</span>
<span class="gp">=&gt; #&lt;Greeter:0x16cac @name="Pat"&gt;</span><span class="w">
</span><span class="gp">irb(main):036:0&gt;</span><span class="w"> </span><span class="n">greeter</span><span class="p">.</span><span class="nf">say_hi</span>
<span class="go">Hi Pat!
</span><span class="p">=&gt;</span> <span class="kp">nil</span>
<span class="gp">irb(main):037:0&gt;</span><span class="w"> </span><span class="n">greeter</span><span class="p">.</span><span class="nf">say_bye</span>
<span class="go">Bye Pat, come back soon.
</span><span class="p">=&gt;</span> <span class="kp">nil</span></code></pre></figure>

Sau khi đối tượng `greeter` được tạo, nó ghi nhớ rằng tên là Pat. Hmm,
nếu chúng ta muốn truy cập trực tiếp vào tên thì sao?

<figure class="highlight"><pre><code class="language-irb" data-lang="irb"><span class="gp">irb(main):038:0&gt;</span><span class="w"> </span><span class="n">greeter</span><span class="o">.</span><span class="vi">@name</span>
<span class="gr">SyntaxError: (irb):38: syntax error, unexpected tIVAR, expecting '('</span></code></pre></figure>

Không, không làm được.

## Bên trong đối tượng

Các biến thực thể được ẩn bên trong đối tượng. Chúng không bị ẩn hoàn
toàn, bạn vẫn thấy chúng khi kiểm tra đối tượng, và cũng có những cách
khác để truy cập chúng, nhưng Ruby sử dụng phương pháp hướng đối tượng
tốt là giữ dữ liệu ở mức tương đối ẩn.

Vậy những method nào tồn tại cho các đối tượng Greeter?

<figure class="highlight"><pre><code class="language-irb" data-lang="irb"><span class="gp">irb(main):039:0&gt;</span><span class="w"> </span><span class="no">Greeter</span><span class="p">.</span><span class="nf">instance_methods</span>
<span class="p">=&gt;</span> <span class="p">[</span><span class="ss">:say_hi</span><span class="p">,</span> <span class="ss">:say_bye</span><span class="p">,</span> <span class="ss">:instance_of?</span><span class="p">,</span> <span class="ss">:public_send</span><span class="p">,</span>
    <span class="ss">:instance_variable_get</span><span class="p">,</span> <span class="ss">:instance_variable_set</span><span class="p">,</span>
    <span class="ss">:instance_variable_defined?</span><span class="p">,</span> <span class="ss">:remove_instance_variable</span><span class="p">,</span>
    <span class="ss">:private_methods</span><span class="p">,</span> <span class="ss">:kind_of?</span><span class="p">,</span> <span class="ss">:instance_variables</span><span class="p">,</span> <span class="ss">:tap</span><span class="p">,</span>
    <span class="ss">:is_a?</span><span class="p">,</span> <span class="ss">:extend</span><span class="p">,</span> <span class="ss">:define_singleton_method</span><span class="p">,</span> <span class="ss">:to_enum</span><span class="p">,</span>
    <span class="ss">:enum_for</span><span class="p">,</span> <span class="ss">:&lt;=&gt;</span><span class="p">,</span> <span class="ss">:===</span><span class="p">,</span> <span class="p">:</span><span class="o">=~</span><span class="p">,</span> <span class="p">:</span><span class="o">!~</span><span class="p">,</span> <span class="ss">:eql?</span><span class="p">,</span> <span class="ss">:respond_to?</span><span class="p">,</span>
    <span class="ss">:freeze</span><span class="p">,</span> <span class="ss">:inspect</span><span class="p">,</span> <span class="ss">:display</span><span class="p">,</span> <span class="ss">:send</span><span class="p">,</span> <span class="ss">:object_id</span><span class="p">,</span> <span class="ss">:to_s</span><span class="p">,</span>
    <span class="ss">:method</span><span class="p">,</span> <span class="ss">:public_method</span><span class="p">,</span> <span class="ss">:singleton_method</span><span class="p">,</span> <span class="ss">:nil?</span><span class="p">,</span> <span class="ss">:hash</span><span class="p">,</span>
    <span class="ss">:class</span><span class="p">,</span> <span class="ss">:singleton_class</span><span class="p">,</span> <span class="ss">:clone</span><span class="p">,</span> <span class="ss">:dup</span><span class="p">,</span> <span class="ss">:itself</span><span class="p">,</span> <span class="ss">:taint</span><span class="p">,</span>
    <span class="ss">:tainted?</span><span class="p">,</span> <span class="ss">:untaint</span><span class="p">,</span> <span class="ss">:untrust</span><span class="p">,</span> <span class="ss">:trust</span><span class="p">,</span> <span class="ss">:untrusted?</span><span class="p">,</span> <span class="ss">:methods</span><span class="p">,</span>
    <span class="ss">:protected_methods</span><span class="p">,</span> <span class="ss">:frozen?</span><span class="p">,</span> <span class="ss">:public_methods</span><span class="p">,</span> <span class="ss">:singleton_methods</span><span class="p">,</span>
    <span class="p">:</span><span class="o">!</span><span class="p">,</span> <span class="ss">:==</span><span class="p">,</span> <span class="p">:</span><span class="o">!=</span><span class="p">,</span> <span class="ss">:__send__</span><span class="p">,</span> <span class="ss">:equal?</span><span class="p">,</span> <span class="ss">:instance_eval</span><span class="p">,</span> <span class="ss">:instance_exec</span><span class="p">,</span> <span class="ss">:__id__</span><span class="p">]</span></code></pre></figure>

Ồ. Nhiều method quá. Chúng ta chỉ định nghĩa có hai method thôi mà.
Chuyện gì đang xảy ra ở đây vậy? Đây là **tất cả** các method của đối
tượng Greeter, một danh sách đầy đủ, bao gồm cả các method được định
nghĩa bởi các class cha. Nếu chúng ta chỉ muốn liệt kê các method
được định nghĩa riêng cho Greeter, chúng ta có thể yêu cầu không bao
gồm các class cha bằng cách truyền tham số `false`, nghĩa là chúng ta
không muốn các method được định nghĩa bởi các class cha.

<figure class="highlight"><pre><code class="language-irb" data-lang="irb"><span class="gp">irb(main):040:0&gt;</span><span class="w"> </span><span class="no">Greeter</span><span class="p">.</span><span class="nf">instance_methods</span><span class="p">(</span><span class="kp">false</span><span class="p">)</span>
<span class="p">=&gt;</span> <span class="p">[</span><span class="ss">:say_hi</span><span class="p">,</span> <span class="ss">:say_bye</span><span class="p">]</span></code></pre></figure>

À, thế mới đúng. Vậy hãy xem đối tượng greeter của chúng ta phản hồi
những method nào:

<figure class="highlight"><pre><code class="language-irb" data-lang="irb"><span class="gp">irb(main):041:0&gt;</span><span class="w"> </span><span class="n">greeter</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="s2">"name"</span><span class="p">)</span>
<span class="p">=&gt;</span> <span class="kp">false</span>
<span class="gp">irb(main):042:0&gt;</span><span class="w"> </span><span class="n">greeter</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="s2">"say_hi"</span><span class="p">)</span>
<span class="p">=&gt;</span> <span class="kp">true</span>
<span class="gp">irb(main):043:0&gt;</span><span class="w"> </span><span class="n">greeter</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="s2">"to_s"</span><span class="p">)</span>
<span class="p">=&gt;</span> <span class="kp">true</span></code></pre></figure>

Vậy là nó biết `say_hi` và `to_s` (nghĩa là chuyển đổi một thứ gì đó
thành chuỗi ký tự, một method được định nghĩa mặc định cho mọi đối
tượng), nhưng nó không biết `name`.

## Thay đổi class — Không bao giờ là quá muộn

Nhưng nếu bạn muốn xem hoặc thay đổi tên thì sao? Ruby cung cấp một
cách dễ dàng để truy cập các biến của đối tượng.

<figure class="highlight"><pre><code class="language-irb" data-lang="irb"><span class="gp">irb(main):044:0&gt;</span><span class="w"> </span><span class="k">class</span> <span class="nc">Greeter</span>
<span class="gp">irb(main):045:1&gt;</span><span class="w">   </span><span class="nb">attr_accessor</span> <span class="ss">:name</span>
<span class="gp">irb(main):046:1&gt;</span><span class="w"> </span><span class="k">end</span>
<span class="p">=&gt;</span> <span class="p">[</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">:name</span><span class="o">=</span><span class="p">]</span></code></pre></figure>

Trong Ruby, bạn có thể mở lại một class và sửa đổi nó. Những thay đổi
sẽ có mặt trong mọi đối tượng mới bạn tạo và thậm chí có sẵn trong các
đối tượng đã tồn tại của class đó. Vậy, hãy tạo một đối tượng mới và
thử nghiệm với thuộc tính `@name` của nó.

<figure class="highlight"><pre><code class="language-irb" data-lang="irb"><span class="gp">irb(main):047:0&gt;</span><span class="w"> </span><span class="n">greeter</span> <span class="o">=</span> <span class="no">Greeter</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s2">"Andy"</span><span class="p">)</span>
<span class="gp">=&gt; #&lt;Greeter:0x3c9b0 @name="Andy"&gt;</span><span class="w">
</span><span class="gp">irb(main):048:0&gt;</span><span class="w"> </span><span class="n">greeter</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="s2">"name"</span><span class="p">)</span>
<span class="p">=&gt;</span> <span class="kp">true</span>
<span class="gp">irb(main):049:0&gt;</span><span class="w"> </span><span class="n">greeter</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="s2">"name="</span><span class="p">)</span>
<span class="p">=&gt;</span> <span class="kp">true</span>
<span class="gp">irb(main):050:0&gt;</span><span class="w"> </span><span class="n">greeter</span><span class="p">.</span><span class="nf">say_hi</span>
<span class="go">Hi Andy!
</span><span class="p">=&gt;</span> <span class="kp">nil</span>
<span class="gp">irb(main):051:0&gt;</span><span class="w"> </span><span class="n">greeter</span><span class="p">.</span><span class="nf">name</span><span class="o">=</span><span class="s2">"Betty"</span>
<span class="p">=&gt;</span> <span class="s2">"Betty"</span>
<span class="gp">irb(main):052:0&gt;</span><span class="w"> </span><span class="n">greeter</span>
<span class="gp">=&gt; #&lt;Greeter:0x3c9b0 @name="Betty"&gt;</span><span class="w">
</span><span class="gp">irb(main):053:0&gt;</span><span class="w"> </span><span class="n">greeter</span><span class="p">.</span><span class="nf">name</span>
<span class="p">=&gt;</span> <span class="s2">"Betty"</span>
<span class="gp">irb(main):054:0&gt;</span><span class="w"> </span><span class="n">greeter</span><span class="p">.</span><span class="nf">say_hi</span>
<span class="go">Hi Betty!
</span><span class="p">=&gt;</span> <span class="kp">nil</span></code></pre></figure>

Sử dụng `attr_accessor` đã định nghĩa hai method mới cho chúng ta,
`name` để lấy giá trị, và `name=` để đặt giá trị.

## Chào hỏi mọi thứ và mọi người, MegaGreeter không bỏ sót ai!

Tuy nhiên, greeter này chưa thực sự thú vị lắm, nó chỉ có thể xử lý
một người tại một thời điểm. Nếu chúng ta có một loại MegaGreeter nào
đó có thể chào cả thế giới, một người, hoặc cả một danh sách người thì
sao?

Hãy viết cái này trong một tệp thay vì trực tiếp trong trình thông dịch
Ruby tương tác IRB.

Để thoát IRB, gõ "quit", "exit" hoặc chỉ cần nhấn Control-D.

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1">#!/usr/bin/env ruby</span>

<span class="k">class</span> <span class="nc">MegaGreeter</span>
  <span class="nb">attr_accessor</span> <span class="ss">:names</span>

  <span class="c1"># Create the object</span>
  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">names</span> <span class="o">=</span> <span class="s2">"World"</span><span class="p">)</span>
    <span class="vi">@names</span> <span class="o">=</span> <span class="n">names</span>
  <span class="k">end</span>

  <span class="c1"># Say hi to everybody</span>
  <span class="k">def</span> <span class="nf">say_hi</span>
    <span class="k">if</span> <span class="vi">@names</span><span class="p">.</span><span class="nf">nil?</span>
      <span class="nb">puts</span> <span class="s2">"..."</span>
    <span class="k">elsif</span> <span class="vi">@names</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="s2">"each"</span><span class="p">)</span>
      <span class="c1"># @names is a list of some kind, iterate!</span>
      <span class="vi">@names</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="nb">name</span><span class="o">|</span>
        <span class="nb">puts</span> <span class="s2">"Hello </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">!"</span>
      <span class="k">end</span>
    <span class="k">else</span>
      <span class="nb">puts</span> <span class="s2">"Hello </span><span class="si">#{</span><span class="vi">@names</span><span class="si">}</span><span class="s2">!"</span>
    <span class="k">end</span>
  <span class="k">end</span>

  <span class="c1"># Say bye to everybody</span>
  <span class="k">def</span> <span class="nf">say_bye</span>
    <span class="k">if</span> <span class="vi">@names</span><span class="p">.</span><span class="nf">nil?</span>
      <span class="nb">puts</span> <span class="s2">"..."</span>
    <span class="k">elsif</span> <span class="vi">@names</span><span class="p">.</span><span class="nf">respond_to?</span><span class="p">(</span><span class="s2">"join"</span><span class="p">)</span>
      <span class="c1"># Join the list elements with commas</span>
      <span class="nb">puts</span> <span class="s2">"Goodbye </span><span class="si">#{</span><span class="vi">@names</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">", "</span><span class="p">)</span><span class="si">}</span><span class="s2">.  Come back soon!"</span>
    <span class="k">else</span>
      <span class="nb">puts</span> <span class="s2">"Goodbye </span><span class="si">#{</span><span class="vi">@names</span><span class="si">}</span><span class="s2">.  Come back soon!"</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>


<span class="k">if</span> <span class="kp">__FILE__</span> <span class="o">==</span> <span class="vg">$0</span>
  <span class="n">mg</span> <span class="o">=</span> <span class="no">MegaGreeter</span><span class="p">.</span><span class="nf">new</span>
  <span class="n">mg</span><span class="p">.</span><span class="nf">say_hi</span>
  <span class="n">mg</span><span class="p">.</span><span class="nf">say_bye</span>

  <span class="c1"># Change name to be "Zeke"</span>
  <span class="n">mg</span><span class="p">.</span><span class="nf">names</span> <span class="o">=</span> <span class="s2">"Zeke"</span>
  <span class="n">mg</span><span class="p">.</span><span class="nf">say_hi</span>
  <span class="n">mg</span><span class="p">.</span><span class="nf">say_bye</span>

  <span class="c1"># Change the name to an array of names</span>
  <span class="n">mg</span><span class="p">.</span><span class="nf">names</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"Albert"</span><span class="p">,</span> <span class="s2">"Brenda"</span><span class="p">,</span> <span class="s2">"Charles"</span><span class="p">,</span>
              <span class="s2">"Dave"</span><span class="p">,</span> <span class="s2">"Engelbert"</span><span class="p">]</span>
  <span class="n">mg</span><span class="p">.</span><span class="nf">say_hi</span>
  <span class="n">mg</span><span class="p">.</span><span class="nf">say_bye</span>

  <span class="c1"># Change to nil</span>
  <span class="n">mg</span><span class="p">.</span><span class="nf">names</span> <span class="o">=</span> <span class="kp">nil</span>
  <span class="n">mg</span><span class="p">.</span><span class="nf">say_hi</span>
  <span class="n">mg</span><span class="p">.</span><span class="nf">say_bye</span>
<span class="k">end</span></code></pre></figure>

Lưu tệp này với tên "ri20min.rb", và chạy bằng lệnh "ruby ri20min.rb".
Kết quả đầu ra sẽ là:

    Hello World!
    Goodbye World.  Come back soon!
    Hello Zeke!
    Goodbye Zeke.  Come back soon!
    Hello Albert!
    Hello Brenda!
    Hello Charles!
    Hello Dave!
    Hello Engelbert!
    Goodbye Albert, Brenda, Charles, Dave, Engelbert.  Come
    back soon!
    ...
    ...
{: .code}

Có rất nhiều thứ mới trong ví dụ cuối cùng này mà chúng ta
[có thể tìm hiểu sâu hơn.](../4/)
