Bazı artıları ve eksileri
Polimorfik için artıları:
- Daha küçük bir polimorfik arayüzün okunması daha kolaydır. Sadece bir yöntemi hatırlamak zorundayım.
- Dilin kullanılması gerektiği yolla gider - Ördek yazımı.
- Bir tavşanı hangi nesnelerden çıkarmak istediğim açıksa, yine de belirsizlik olmamalıdır.
- Sihirbazın tavşan çıkardığı nesnelerin türünü ayırt etmesi gerektiğinde, nesnenin türü için çok sayıda tür kontrolünün çirkin kod oluşturduğu Java gibi statik dillerde bile çok fazla tür denetimi yapmak kötü kabul edilir. ?
Geçici için artıları:
- Daha az belirgindir, bir dizeden bir
Cat
örnek alabilir miyim? Sadece işe yarar mı? değilse, davranış nedir? Buradaki türü sınırlamazsam, bunu belgelerde veya daha kötü bir sözleşme yapabilecek testlerde yapmak zorundayım.
- Bir tavşanı tek bir yerde çekmek için tüm işlemlere sahipsiniz, Sihirbaz (bazıları bunu bir con olarak düşünebilir)
- Modern JS optimizasyonları monomorfik (sadece bir tipte çalışır) ve polimorfik fonksiyonlar arasında farklılık gösterir. Onlar monomorfik olanları nasıl optimize biliyorum çok böylece daha iyi
pullRabbitOutOfString
versiyonu olma olasılığı çok V8 gibi motorlarında daha hızlı. Daha fazla bilgi için bu videoyu izleyin. Düzenleme: Kendime bir mükemmel yazdım , pratikte bu her zaman böyle değil .
Bazı alternatif çözümler:
Bence, bu tür bir tasarım başlamak için çok fazla 'Java-Scripty' değil. JavaScript, C #, Java veya Python gibi dillerden farklı deyimlere sahip farklı bir dildir. Bu deyimler, dilin zayıf ve güçlü kısımlarını anlamaya çalışan geliştiricilerin yıllarından kaynaklanır, yapacağım şey bu deyimlere bağlı kalmaya çalışmaktır.
Düşünebileceğim iki güzel çözüm var:
- Nesneleri kaldırmak, nesneleri "ezilebilir" yapmak, onları çalışma zamanında bir arayüze uydurmak, ardından Sihirbazın ezilebilir nesneler üzerinde çalışması.
- Strateji modelini kullanarak Büyücüye farklı türdeki nesnelerin nasıl işleneceğini dinamik olarak öğretin.
Çözüm 1: Nesneleri Kaldırma
Bu soruna ortak bir çözüm, tavşanları çekip çıkarma yeteneğiyle nesneleri 'yükseltmektir'.
Yani, bir tür nesne alan ve onun için şapkadan çekmeyi ekleyen bir işleve sahip olmak. Gibi bir şey:
function makePullable(obj){
obj.pullOfHat = function(){
return new Rabbit(obj.toString());
}
}
Ben makePullable
diğer nesneler için böyle işlevler yapabilirsiniz , ben oluşturabilir makePullableString
, vb. Ben her tür üzerinde dönüşüm tanımlamak. Ancak, nesnelerimi yükselttikten sonra, bunları genel bir şekilde kullanacak bir türüm yok. JavaScript bir arayüz, bir varsa, bir ördek yazarak tarafından belirlenir pullOfHat
yöntemi ben yapabilirsiniz Magician'ların yöntemiyle çekin.
Sonra Sihirbaz yapabilirdi:
Magician.pullRabbit = function(pullable) {
var rabbit = obj.pullOfHat();
return {rabbit:rabbit,text:"Tada, I pulled a rabbit out of "+pullable};
}
Nesneleri yükseltmek, bir çeşit mixin deseni kullanmak daha fazla JS işi gibi görünüyor. (Bunun dilde, sayı, null, undefined ve boolean dilde değer türleriyle ilgili sorunlu olduğunu unutmayın, ancak hepsi kutuda kullanılabilir)
İşte böyle bir kodun nasıl görünebileceğine bir örnek
Çözüm 2: Strateji Kalıbı
StackOverflow'daki JS sohbet odasında bu soruyu tartışırken arkadaşım fenomnomnominal Strateji modelinin kullanılmasını önerdi .
Bu, çalışma zamanında tavşanları çeşitli nesnelerden çekme yeteneklerini eklemenize izin verir ve çok JavaScript kodu oluşturur. Bir sihirbaz, farklı tipteki nesnelerin şapkadan nasıl çekileceğini öğrenebilir ve onları bu bilgiye dayanarak çeker.
Bu, CoffeeScript'te şöyle görünebilir:
class Magician
constructor: ()-> # A new Magician can't pull anything
@pullFunctions = {}
pullRabbit: (obj) -> # Pull a rabbit, handler based on type
func = pullFunctions[obj.constructor.name]
if func? then func(obj) else "Don't know how to pull that out of my hat!"
learnToPull: (obj, handler) -> # Learns to pull a rabbit out of a type
pullFunctions[obj.constructor.name] = handler
Eşdeğer JS kodunu burada görebilirsiniz .
Bu şekilde, her iki dünyadan da faydalanırsınız, nasıl çekileceği eylemi nesnelere veya Sihirbaza sıkı sıkıya bağlı değildir ve bence bu çok güzel bir çözüm sağlar.
Kullanım şöyle bir şey olurdu:
var m = new Magician();//create a new Magician
//Teach the Magician
m.learnToPull("",function(){
return "Pulled a rabbit out of a string";
});
m.learnToPull({},function(){
return "Pulled a rabbit out of a Object";
});
m.pullRabbit(" Str");