SORU
17 Aralık 2010, Cuma


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
17 Aralık 2010, Cuma


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ü (UnboundMethods ç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 bareriş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'

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Evan Coury

    Evan Coury

    29 NİSAN 2007
  • Propaganda Time

    Propaganda T

    19 EYLÜL 2010
  • Video-Tutorials.Net

    Video-Tutori

    15 Mart 2011