Maymun bir yöntem yama, yeni uygulama geçersiz kılınmış yöntemi denilebilir mi?
Maymun yama ben bir sınıf içinde bir yöntem, nasıl geçersiz kılma yöntemi geçersiz kılınmış yöntemi diyebilir miyim? I. e. Biraz super
gibi bir ÅŸey
E. g.
class Foo
def bar()
"Hello"
end
end
class Foo
def bar()
super() " World"
end
end
>> Foo.new.bar == "Hello World"
CEVAP
Bu diyemezsinüzerineadı veya anahtar kelime tarafından yöntemi. Bu kaçınılmalıdır neden birçok nedenlerden biri ve miras yerine, gerekirse seni tercih edilmelidirolabilirçağrıgeçersiz kılınmışyöntem.
Miras
Bu yüzden mümkünse, böyle bir şey tercih etmelisiniz:
class Foo
def bar
'Hello'
end
end
class ExtendedFoo < Foo
def bar
super ' World'
end
end
ExtendedFoo.new.bar # => 'Hello World'
Bu ise Foo
nesneler varsa çalışır. Sadece değişim Foo
yerine ExtendedFoo
bir oluşturmak için yaratan her yer. Bu Bağımlılık Enjeksiyon Tasarım Deseni kullanırsanız daha iyi olur, Fabrika Yöntemi Tasarım Deseni, Fabrika Tasarım Deseni veya bu satırlar boyunca bir şey için çalışır.
Heyet
Eğeryokkontrol yaratılış Foo
nesneler, örneğin, çünkü onlar tarafından oluşturulan bir çerçeve olması dışında kontrol (Ruby on Rails örneğin), daha sonra kullanmak Sarıcı Tasarım Deseni:
require 'delegate'
class Foo
def bar
'Hello'
end
end
class WrappedFoo < DelegateClass(Foo)
def initialize(wrapped_foo)
super
end
def bar
super ' World'
end
end
foo = Foo.new # this is not actually in your code, it comes from somewhere else
wrapped_foo = WrappedFoo.new(foo) # this is under your control
wrapped_foo.bar # => 'Hello World'
Foo
nesne kodu haline geldiğini temelde, sistem sınırları,,, başka bir nesnenin içine sarın ve kullanınbuorijinal kodu her yerde yerine nesne.
Miras (kırık) kendisine dahil ederse
Böyle bir şey yapmak için cazip olabilir:
class Foo
def bar
'Hello'
end
end
module FooExtensions
def bar
super ' World'
end
end
class Foo
include FooExtensions
end
Ne yazık ki, işe yaramaz. super
kullanabilirsiniz anlamına gelir, miras, kullandığı için iyi bir fikirdir. Ancak, include
ekler kendisine dahil ederseyukarıdaFooExtensions#bar
hiç aramadı olacağı anlamına gelir, miras hiyerarşisini, (ve eğer . sınıf ^em>edildidenilen super
aslında var olmayan Object#bar
26 *ama değil) bakın, Foo#bar
Her zaman ilk bulunacaktır beri.
29* *zincir
Bizim maymun yama ile yaşıyorsanız sorun yöntem üzerine yöntem gitmiş olmasıdır, biz artık diyoruz. Sadece yedek bir kopyasını yapın hadi!
class Foo
def bar
'Hello'
end
end
class Foo
alias_method :old_bar, :bar
def bar
old_bar ' World'
end
end
Foo.new.bar # => 'Hello World'
Foo.new.old_bar # => 'Hello'
Bu sorunu ÅŸimdi old_bar
gereksiz bir yöntem ile Ad kirli olması. Bu yöntem bizim belgelerinde, bizim IDE kod tamamlama içinde ortaya çıkacak, yansıma sırasında ortaya çıkacaktır. Ayrıca, hala çağrılabilir, ama muhtemelen biz diğer insanların bunu söylemek zorunda kaldığım için değil bu yüzden ilk başta onun davranış gibi değil. maymun yamalı.
Yöntemi Ambalaj
Yani, büyük soru şu: nasıl aslında bir tutma olmadan bar
yöntemi tut, biz de yapabilirizgerçek yöntemi? Cevap çok sık yaptığı gibi fonksiyonel programlama yatıyor. Gerçek bir yöntemi ele alacağıznesnebir kapatma (yani blok) biz emin olmak için kullanıyoruzve biz sadecebu nesne tutun:
class Foo
def bar
'Hello'
end
end
class Foo
old_bar = instance_method(:bar)
define_method(:bar) do
old_bar.bind(self).() ' World'
end
end
Foo.new.bar # => 'Hello World'
Yöntemlerini kullanan gerçek maymun yama yerine miras ya da heyet, bu temiz: beri old_bar
sadece bir yerel değişken, gidecek kapsam sonunda sınıf beden ve imkansız erişimi her yerdebileyansıtma! Ve define_method
bir blok alır ve blok etrafındaki sözlü çevreleri üzerinde yakın zamandan beri olanneden37 ** burada) yerine define_method
kullanıyoruz(vesadecebunu hala kapsam dışına gitti sonra bile 38**, erişimi olacaktır.
Kısa açıklama:
old_bar = instance_method(:bar)
Burada UnboundMethod
yöntem bir nesnenin içine bar
yöntemi sarma ve yerel değişken old_bar
atama. Bu, biz şimdi bunun üzerine sonra bile bar
tutmak için bir yol anlamına gelir.
old_bar.bind(self)
Bu biraz zor. Temelde, Ruby (ve hemen hemen tek Merkez tabanlı OO dilde), bir yöntem, belirli bir alıcı bir nesne, Ruby self
adlı bağlıdır. Bir yöntem her zaman denilen nesne ne olduğunu bilir, self
onun ne olduğunu biliyor. başka bir deyişle: Doğrudan bir sınıf yöntemi yakaladık ama, nasıl self
onun ne olduÄŸunu biliyor mu?
O zaman arayabileceÄŸimiz Method
bir nesne döndürür bir nesne önce bind
UnboundMethod
ihtiyacım var neden mi, değil. Onların haberi olmadan ne yapacağımı bilmiyorum, çünkü (UnboundMethod
s çağrılamaz, self
.)
Ve biz 53 ** bu ne? Biz sadece 54* *kendimize, davranacaktırtam olarakorijinal gibi bar
olurdu!
Son olarak, bind
döndürülen Method
aramalıyız. Ruby 1.9, orada bazı şık yeni sözdizimi için (.()
), ama eÄŸer 1.8, sadece call
yöntemi; bu ne .()
alır çevrilmiş zaten.
İşte bu kavramların bazıları açıklanıyor, diğer soru, bir çift vardır:
Gelecek: Ruby 2.0
Ruby bunu söylemek kolay bir yolu var 2.0,.
Module#prepend
: kendisine dahil ederse, Miras (sabit)
Sadece miras, yeni anahtar kelimeler, yöntem combinators, yeni bir anlambilim ya da böyle bir şey için gerek kalmadan kullanır, çünkü bunu seviyorum.
Yukarıda unutmayınMiras (kırık) kendisine dahil edersesorun kendisine dahil ederse yerleştirilir olduğunu söylediğimizde bölümyukarıdadevralma hiyerarşisinde sınıf? İyi, Module#prepend
sadece doğrudan modülde karışımları hariç Module#include
, aynı şeyi yapan yeni bir yöntemdiraşağıdasınıfı:
class Foo
def bar
'Hello'
end
end
module FooExtensions
def bar
super ' World'
end
end
class Foo
prepend FooExtensions # the only change to above: prepend instead of include
end
Foo.new.bar # => 'Hello World'
Bu kodu kendine YARV kaynak kodunun ana şube yeni bir ödeme almak ve derlemek aslında şu an çalışıyor.
Yeniden bağlamanız modül yöntemi
Bağlama yöntemleri ancak onlar her zaman sınıfın aynı sınıf veya mirasçısı olacak önceki Ruby sürümlerinde kullanılabilir. Ruby 2.0 bu yana herhangi bir modül yöntemi yeniden bağlayın
module Foo
def bar
"Hello #{who}"
end
end
class Car
def bar
'Different hello'
end
def who
'Tomas'
end
end
car = Car.new
car.bar # => 'Different hello'
Foo.instance_method(:bar).bind(car).call # => "Hello Tomas"
car.bar # => 'Different hello'
RakipNon-RubyFikirler
Yöntem Combinators
Bir fikir CLOS yöntem combinators fikri. Bu temelde En-Boy-Yönelimli Programlama alt çok hafif bir versiyonu.
Sözdizimini kullanarak gibi
class Foo
def bar:before
# will always run before bar, when bar is called
end
def bar:after
# will always run after bar, when bar is called
# may or may not be able to access and/or change bar's return value
end
end
"bar
yöntem." yürütme kanca mümkün olacaktır
Ancak bar
eriÅŸim ve's bar:after
içinde değerini döndürür. eğer çok açıktır Belki (ab) super
anahtar kelimeyi kullanabiliriz?
class Foo
def bar
'Hello'
end
end
class Foo
def bar:after
super ' World'
end
end
old
anahtar kelime
Bu fikir yeni bir anahtar kelime arama saÄŸlar super
benzer eklerüzerineyöntem aynı şekilde super
arama sağlargeçersiz kılınmışyöntem:
class Foo
def bar
'Hello'
end
end
class Foo
def bar
old ' World'
end
end
Foo.new.bar # => 'Hello World'
Yöntem old
denilen varsa artık onu çağırmak mümkün olacak! bu geriye doğru uyumlu olmasıdır asıl sorun:
redef
anahtar kelime
Yukarıda benzer, ama yeni bir anahtar kelime eklemek yerinearamaüzerine yöntem ve yalnız def
bırakarak, yeni bir kelime ekliyoruzyeniden tanımlıyoryöntemleri. Bu sözdizimi şu anda zaten yasadışı olduğu için Geriye doğru uyumludur:
class Foo
def bar
'Hello'
end
end
class Foo
redef bar
old ' World'
end
end
Foo.new.bar # => 'Hello World'
Eklemek yerineikiyeni kelimeler de redef
içinde super
anlamını yeniden tanımlama yapabiliriz:
class Foo
def bar
'Hello'
end
end
class Foo
redef bar
super ' World'
end
end
Foo.new.bar # => 'Hello World'
Kötü uygulama geçersiz bir yöntem için...
Aynı yöntem ile bir sınıfta iki arabir...
ObjC Kategori üzerinden bir yöntemi ge...
'Eclipse içine bir proje aldıktan...
Geçersiz kılınmış bir Sistem için en i...