Klon'u Ruby'de prototip tabanlı programlama yapmak için kullanabilirsiniz. Ruby'nin Object sınıfı hem klon yöntemini hem de dup yöntemini tanımlar. Hem klon hem de dup, kopyaladığı nesnenin sığ bir kopyasını üretir; yani, nesnenin örnek değişkenleri kopyalanır, ancak başvurdukları nesneler kopyalanmaz. Bir örnek göstereceğim:
class Apple
attr_accessor :color
def initialize
@color = 'red'
end
end
apple = Apple.new
apple.color
=> "red"
orange = apple.clone
orange.color
=> "red"
orange.color << ' orange'
=> "red orange"
apple.color
=> "red orange"
Yukarıdaki örnekte, turuncu klon, elma nesnesinin durumunu (yani, örnek değişkenleri) kopyalar, ancak elma nesnesinin diğer nesnelere (Dize nesnesi rengi gibi) başvurduğu yerlerde, bu başvurular kopyalanmaz. Bunun yerine, elma ve portakal aynı nesneyi ifade ediyor! Örneğimizde, referans 'kırmızı' dize nesnesidir. Turuncu, varolan String nesnesini değiştirmek için ekleme yöntemini << kullandığında, dize nesnesini 'kırmızı turuncu' olarak değiştirir. Her ikisi de aynı String nesnesini işaret ettiğinden, bu aslında apple.color'u da değiştirir.
Bir yan not olarak, atama operatörü =, yeni bir nesne atar ve böylece bir referansı yok eder. İşte bir gösteri:
class Apple
attr_accessor :color
def initialize
@color = 'red'
end
end
apple = Apple.new
apple.color
=> "red"
orange = apple.clone
orange.color
=> "red"
orange.color = 'orange'
orange.color
=> 'orange'
apple.color
=> 'red'
Yukarıdaki örnekte, turuncu klonun renk örneği yöntemine yeni bir nesne atadığımızda, artık elma ile aynı nesneye başvurmuyor. Bu nedenle, şimdi, elmanın renk yöntemini etkilemeden portakalın renk yöntemini değiştirebiliriz, ancak elmadan başka bir nesneyi klonlarsak, bu yeni nesne, kopyalanan örnek değişkenlerindeki elma ile aynı nesnelere başvuracaktır.
dup, kopyaladığı nesnenin sığ bir kopyasını da üretir ve dup için yukarıda gösterilenle aynı gösterimi yaparsanız, tam olarak aynı şekilde çalıştığını görürsünüz. Ancak klon ve dup arasında iki büyük fark vardır. Birincisi, diğerlerinin de belirttiği gibi, klon dondurulmuş durumu kopyalar ve dup kopyalamaz. Ne anlama geliyor? Ruby'de 'dondurulmuş' terimi değişmez için ezoterik bir terimdir, ki bu da bilgisayar biliminde bir terminolojidir, yani bir şeyin değiştirilemeyeceği anlamına gelir. Böylece, Ruby'deki donmuş bir nesne hiçbir şekilde değiştirilemez; aslında değişmezdir. Dondurulmuş bir nesneyi değiştirmeye çalışırsanız, Ruby bir RuntimeError istisnası oluşturur. Klon dondurulmuş durumu kopyaladığından, klonlanmış bir nesneyi değiştirmeye çalışırsanız, bir RuntimeError istisnası yükselir. Tersine, dup dondurulmuş durumu kopyalamadığından,
class Apple
attr_accessor :color
def initialize
@color = 'red'
end
end
apple = Apple.new
apple.frozen?
=> false
apple.freeze
apple.frozen?
=> true
apple.color = 'crimson'
RuntimeError: can't modify frozen Apple
apple.color << ' crimson'
=> "red crimson" # we cannot modify the state of the object, but we can certainly modify objects it is referencing!
orange = apple.dup
orange.frozen?
=> false
orange2 = apple.clone
orange2.frozen?
=> true
orange.color = 'orange'
=> "orange" # we can modify the orange object since we used dup, which did not copy the frozen state
orange2.color = 'orange'
RuntimeError: can't modify frozen Apple # orange2 raises an exception since the frozen state was copied via clone
İkincisi, ve daha ilginç bir şekilde, klon singleton sınıfını (ve dolayısıyla yöntemlerini) kopyalar! Ruby'de prototip tabanlı programlama yapmak istiyorsanız bu çok yararlıdır. İlk olarak, gerçekten de singleton yöntemlerinin klonla kopyalandığını gösterelim ve sonra bunu Ruby'deki prototip tabanlı programlama örneğinde uygulayabiliriz.
class Fruit
attr_accessor :origin
def initialize
@origin = :plant
end
end
fruit = Fruit.new
=> #<Fruit:0x007fc9e2a49260 @origin=:plant>
def fruit.seeded?
true
end
2.4.1 :013 > fruit.singleton_methods
=> [:seeded?]
apple = fruit.clone
=> #<Fruit:0x007fc9e2a19a10 @origin=:plant>
apple.seeded?
=> true
Gördüğünüz gibi, meyve nesnesi örneğinin singleton sınıfı klonuna kopyalanır. Ve böylece klonlanmış nesnenin singleton yöntemine erişimi vardır: tohumlanmış? Ancak dup ile durum böyle değil:
apple = fruit.dup
=> #<Fruit:0x007fdafe0c6558 @origin=:plant>
apple.seeded?
=> NoMethodError: undefined method `seeded?'
Şimdi prototip tabanlı programlamada, diğer sınıfları genişleten ve daha sonra yöntemleri bir plan görevi gören bir üst sınıftan türetilen sınıf örnekleri oluşturan sınıflarınız yoktur. Bunun yerine, bir temel nesneniz var ve daha sonra nesnelerle yöntemleri ve kopyalanan durumu ile yeni bir nesne oluşturuyorsunuz (elbette, klon yoluyla sığ kopyalar yaptığımız için, örnek değişkenlerinin başvurduğu tüm nesneler JavaScript'te olduğu gibi paylaşılacaktır prototipler). Daha sonra, klonlanan yöntemlerin ayrıntılarını doldurarak nesnenin durumunu doldurabilir veya değiştirebilirsiniz. Aşağıdaki örnekte, temel meyve nesnesimiz var. Tüm meyvelerin tohumları vardır, bu nedenle tohumlar_sayısı için bir yöntem oluştururuz. Ancak elmanın bir tohumu var ve bu yüzden bir klon yaratıyoruz ve ayrıntıları dolduruyoruz. Elmayı klonladığımızda, sadece yöntemleri klonlamakla kalmadık, aynı zamanda durumu klonladık! Klonun durumun sığ bir kopyasını yaptığını unutmayın (örnek değişkenler). Ve bu nedenle, bir red_apple elde etmek için elmayı klonladığımızda, red_apple otomatik olarak 1 çekirdeğe sahip olacak! Red_apple'ı, Apple'dan miras alan ve karşılığında Fruit'ten miras alan bir nesne olarak düşünebilirsiniz. Bu yüzden Fruit ve Apple'dan büyük harf aldım. Sınıflar ve nesneler arasındaki klonun izniyle ayrıldık.
Fruit = Object.new
def Fruit.number_of_seeds=(number_of_seeds)
@number_of_seeds = number_of_seeds
end
def Fruit.number_of_seeds
@number_of_seeds
end
Apple = Fruit.clone
=> #<Object:0x007fb1d78165d8>
Apple.number_of_seeds = 1
Apple.number_of_seeds
=> 1
red_apple = Apple.clone
=> #<Object:0x007fb1d892ac20 @number_of_seeds=1>
red_apple.number_of_seeds
=> 1
Tabii ki, prototip tabanlı programlamada bir yapıcı yöntemine sahip olabiliriz:
Fruit = Object.new
def Fruit.number_of_seeds=(number_of_seeds)
@number_of_seeds = number_of_seeds
end
def Fruit.number_of_seeds
@number_of_seeds
end
def Fruit.init(number_of_seeds)
fruit_clone = clone
fruit_clone.number_of_seeds = number_of_seeds
fruit_clone
end
Apple = Fruit.init(1)
=> #<Object:0x007fcd2a137f78 @number_of_seeds=1>
red_apple = Apple.clone
=> #<Object:0x007fcd2a1271c8 @number_of_seeds=1>
red_apple.number_of_seeds
=> 1
Sonuçta, klon kullanarak JavaScript prototip davranışına benzer bir şey elde edebilirsiniz.
dup
veclone
yapar, ancak neden diğer yerine birini kullanmayı tercih ediyorum.