Yukihiro "Matz" Matsumoto

Often people, especially computer engineers, focus on the machines. They think, "By doing this, the machine will run fast. By doing this, the machine will run more effectively. By doing this, the machine will something something something." They are focusing on machines. But in fact we need to focus on humans, on how humans care about doing programming or operating the application of the machines. We are the masters. They are the slaves.
Yukihiro "Matz" Matsumoto, Creator of Ruby

Rabu, 08 Oktober 2014

Melakukan Copy Objek Dalam Array Dengan Reference Baru Pada Custom Class Ruby

Ruby adalah bahasa pemrograman yang sangat kuat didalam dasar Object Oriented Paradigm. Dalam Ruby, kita dapat menciptakan enkapsulasi dari suatu objek yang kita inginkan dalam kelas yang dapat kita buat sendiri.

Pada tips kali ini, saya ingin memberikan tips mengenai pointer atau reference bagi anda yang menggunakan container object yang berisi objek-objek yang ingin anda copy ke dalam container tersebut dengan memberikan referensi/pointer baru sehingga apabila anda melakukan modifikasi pada objek awal, maka tidak akan mempengaruhi objek yang ada didalam container tersebut. 

Sebagai ilustrasi, misalnya anda memiliki objek dengan kelas Person, maka dalam pendekatan Object Oriented kita dapat membuat kelas container berupa Group yang berisi sekumpulan objek Person.

Secara default, saat kita memasukkan objek standard ruby seperti String, Fixnum, dan Float ke dalam sebuah array, maka objek yang akan kita masukkan akan memiliki referensi yang sama dengan objek yang ada didalam array tersebut

irb > x = 5
irb > x.object_id
=> 11

Angka yang dihasilkan ini merupakan lokasi dimana variabel anda disimpan dalam RAM komputer anda. Berikut kita akan memasukkan variabel ini ke dalam sebuah array

irb > numbers = []
irb > numbers << x
irb > numbers[0].object_id
=> 11

Dapat dilihat bahwa objek yang dimasukkan didalam array memiliki referensi yang sama dengan variabel yang dimasukkan. Berikut saya akan memberikan nilai yang baru dalam variabel x.

irb > x = 7
irb > x.object_id 
=> 20
irb > numbers[0].object_id
=> 11

Dari hasil yang terlihat, variabel x sekarang merujuk pada lokasi referensi yang baru didalam RAM anda sedangkan variabel yang telah dimasukkan ke dalam array memiliki referensi yang tetap sama.

Berikut saya akan masuk ke bagian utama, saya akan membuat 2 kelas baru, yang pertama merupakan kelas Person. Kelas ini memiliki instance variabel berupa nama. Yang kedua, saya akan membuat kelas container berupa Group yang akan memiliki instance variabel berupa nama group dan sebuah array yang akan menampung objek-objek Person yang akan dimasukkan dalam group. Terdapat juga instance method add_person yang akan menerima argumen objek yang akan dimasukkan ke dalam array people dalam group.

irb > class Person
irb >   attr_accessor :name
irb >   def initialize(name)
irb >     @name = name
irb >   end
irb > end

irb > class Group
irb >   attr_accessor :people
irb >   def initialize(name)
irb >     @name = name
irb >     @people = []
irb >   end
irb >   def add_person(people)
irb >     @people << people
irb >   end
irb > end

Berikutnya kita akan membuat tiga objek person yang akan dimasukkan ke dalam objek group dan kita akan mencoba untuk mengubah nama dari objek awal yang telah kita masukkan ke dalam objek grup untuk melihat apa yang akan dihasilkan.

irb > person1 = Person.new("Barry")
=> #<Person:0x007fc2e40b8b88 @name="Barry">
irb > person2 = Person.new("Leon")
=> #<Person:0x007fc2e40a9b38 @name="Leon">
irb > person3 = Person.new("Chris")
=> #<Person:0x007fc2e409b178 @name="Chris">
irb > group = Group.new("Zombie Hunters")
=> #<Group:0x007fc2e408a5a8 @name="Zombie Hunters", @people=[]>
irb > group.add_person(person1)
=> [#<Person:0x007fc2e40b8b88 @name="Barry">]
irb > group.add_person(person2)
=> [#<Person:0x007fc2e40b8b88 @name="Barry">, #<Person:0x007fc2e40a9b38 @name="Leon">]
irb > group.add_person(person3)
=> [#<Person:0x007fc2e40b8b88 @name="Barry">, #<Person:0x007fc2e40a9b38 @name="Leon">, #<Person:0x007fc2e409b178 @name="Chris">]
irb > person1.name = "Jill"
irb > grup
=> #<Group:0x007fc2e408a5a8 @name="Zombie Hunters", @people=[#<Person:0x007fc2e40b8b88 @name="Jill">, #<Person:0x007fc2e40a9b38 @name="Leon">, #<Person:0x007fc2e409b178 @name="Chris">]>
irb > person1.object_id
=> 70237513172420
irb > grup.people[0].object_id
=> 70237513172420

Dapat kita lihat apabila kita melakukan perubahan pada objek person1 maka objek yang telah ada di dalam objek grup juga akan mengalami perubahan. Dapat kita lihat pada objek id yang ada bahwa kedua objek tersebut tetap memiliki referensi yang sama yang ada didalam RAM komputer anda.

Hal ini terjadi karena pada saat anda melakukan perubahan nama yang ada dalam instance variabel pada objek Person, maka objek ini yang akan berubah referensinya didalam RAM, sedangkan objek Person tetap memiliki referensi yang sama didalam RAM anda. Hal ini mengakibatkan apabila anda mengubah salah satu instance variabel dalam objek Person anda maka objek yang telah dimasukkan ke dalam instance variabel array dalam objek group anda akan tetap merujuk pada referensi yang sama dalam memori komputer anda.  Tetapi ingat, apabila anda menciptakan Objek movie baru pada variabel person1 anda maka variabel tersebut akan memiliki referensi baru dalam memori anda dan tidak mempengaruhi objek yang ada didalam objek grup, seperti terlihat dibawah ini.

irb > person2 = Person.new("Claire")
irb > grup
#<Group:0x007fc2e408a5a8 @name="Zombie Hunters", @people=[#<Person:0x007fc2e40b8b88 @name="Jill">, #<Person:0x007fc2e40a9b38 @name="Leon">, #<Person:0x007fc2e409b178 @name="Chris">]>

Bagi anda yang ingin menghindari pass by reference oleh custom object ini pada saat anda memasukkan suatu objek dalam kontainer objek, anda dapat menggunakan method clone dalam kelas yang anda ingin copy dalam kelas kontainer. Method ini melakukan cloning dengan menciptakan objek dengan referensi baru dengan instance variable yang sama. Implementasinya dapat dilihat dibawah ini.

irb > class Person
irb >   attr_accessor :name
irb >   def initialize(name)
irb >     @name = name
irb >   end
irb > 
irb>   def clone
irb>     Person.new(self.name)
irb>   end
irb> end


Didalam kelas kontainer kita dapat memanggil method clone saat kita ingin memasukkan objek ke dalam array kontainer objek kita.

irb > class Group
irb >   attr_accessor :people
irb >   def initialize(name)
irb >     @name = name
irb >     @people = []
irb >   end
irb >   
irb <   def add_person(name)
irb >     @people << name.clone
irb >   end
irb > end

Dengan melakukan metode ini kita tidak perlu lagi memikirkan referensi objek yang kita copy ke dalam kontainer objek disaat kita melakukan perubahan pada objek tersebut. Objek yang dimasukkan ke dalam kontainer objek akan memiliki referensi baru yang berbeda dengan objek yang dimasukkan ke dalam kontainer.

irb > person1 = Person.new("Barry")
=> #<Person:0x007fc2e40b8b88 @name="Barry">
irb > person2 = Person.new("Leon")
=> #<Person:0x007fc2e40a9b38 @name="Leon">
irb > person3 = Person.new("Chris")
=> #<Person:0x007fc2e409b178 @name="Chris">
irb > group = Group.new("Zombie Hunters")
=> #<Group:0x007fc2e408a5a8 @name="Zombie Hunters", @people=[]>
irb > group.add_person(person1)
=> [#<Person:0x007fc2e40b8999 @name="Barry">]
irb > group.add_person(person2)
=> [#<Person:0x007fc2e40b8b88 @name="Barry">, #<Person:0x007fc2e40a9b38 @name="Leon">]
irb > group.add_person(person3)
=> [#<Person:0x007fc2e40b8b88 @name="Barry">, #<Person:0x007fc2e40a9b38 @name="Leon">, #<Person:0x007fc2e409b178 @name="Chris">]
irb > person1.name = "Jill"
irb > grup
=> #<Group:0x007fc2e408a5a8 @name="Zombie Hunters", @people=[#<Person:0x007fc2e40b8999 @name="Barry">, #<Person:0x007fc2e40a9b38 @name="Leon">, #<Person:0x007fc2e409b178 @name="Chris">]>
irb > person1.object_id
=> 70237513172831
irb > grup.people[0].object_id
=> 70237513172134















Tidak ada komentar:

Posting Komentar