Soru Yapıcı işlevi vs Fabrika fonksiyonları


Birisi, bir yapıcı işlevi ile Javascript'teki bir fabrika işlevi arasındaki farkı açıklayabilir.

Bir diğerini ne zaman kullanmalı?


121
2018-01-02 08:19


Menşei




Cevaplar:


Temel fark, bir yapıcı işlevinin new anahtar kelime (JavaScript'in otomatik olarak yeni bir nesne oluşturmasına neden olan this Bu nesnenin işlevi içinde ve nesneyi döndürür):

var objFromConstructor = new ConstructorFunction();

Bir fabrika işlevi "normal" işlev gibi çağrılır:

var objFromFactory = factoryFunction();

Ama bunun bir "fabrika" olarak görülmesi için, bir nesnenin yeni bir örneğini döndürmesi gerekecek: bir boolean ya da bir şey döndürdüyse, buna "fabrika" işlevi diyemezsiniz. Bu, otomatik olarak gerçekleşmez newAncak bazı durumlarda daha fazla esneklik sağlar.

Gerçekten basit bir örnekte, yukarıda atıfta bulunulan işlevler şöyle bir şeye benzeyebilir:

function ConstructorFunction() {
   this.someProp1 = "1";
   this.someProp2 = "2";
}
ConstructorFunction.prototype.someMethod = function() { /* whatever */ };

function factoryFunction() {
   var obj = {
      someProp1 : "1",
      someProp2 : "2",
      someMethod: function() { /* whatever */ }
   };
   // other code to manipulate obj in some way here
   return obj;
}

Elbette fabrika fonksiyonlarını bu basit örnekten daha karmaşık hale getirebilirsiniz.

Bazı insanlar fabrika işlevlerini her şey için kullanmayı tercih ediyorlar çünkü kullanmayı hatırlamaktan hoşlanmıyorlar. new (DÜZENLE: ve bu bir sorun olabilir çünkü new işlev hala çalışır ancak beklendiği gibi olmaz). Bunu bir avantaj olarak görmüyorum: new dilin çekirdek bir parçasıdır, bu yüzden benim için kasıtlı olarak kaçınmak biraz keyfi - diğer anahtar kelimeler gibi kaçınmak gibi else.

Fabrika işlevlerinin bir avantajı, döndürülecek nesnenin bazı parametrelere bağlı olarak birkaç farklı türde olması olabilir.


131
2018-01-02 09:07



"(DÜZENLEME: ve bu bir sorun olabilir, çünkü yeni fonksiyon olmaksızın hala çalışır fakat beklendiği gibi olmaz." Bu, "new" ile bir fabrika işlevini çağırmaya çalıştığınızda veya örneğe atamak için "this" anahtar sözcüğünü kullanmaya çalıştığınızda sorun olur. Aksi takdirde, sadece yeni, keyfi bir nesne yaratır ve geri döndürürsünüz. Sorun yok, işleri daha az, daha az kalıbı olan ve API'ye anlık bilgi ayrıntılarını sızdırmayan farklı, daha esnek bir yol. - Eric Elliott
Her iki durum için de örneklerin (yapıcı fonksiyonu vs fabrika fonksiyonu) tutarlı olması gerektiğine işaret etmek istedim. Fabrika işlevi için örnek içermez someMethod Fabrika tarafından döndürülen nesneler için, ve biraz sisli olduğu yer burası. Fabrika işlevinin içinde, eğer sadece biri var obj = { ... , someMethod: function() {}, ... }Bu, döndürülen her bir nesnenin farklı bir kopyasına sahip olmasını sağlar someMethod istemeyebileceğimiz bir şey. Kullanıldığı yer burası new ve prototype Fabrika içi işlevi yardımcı olacaktır. - Bharat Khatri
Daha önce de belirttiğiniz gibi, bazı insanlar fabrika işlevlerini kullanmayı deniyor, çünkü insanların kullanmayı unutacakları hataları bırakmıyorlar. new yapıcı işlevi ile; Birinin görülmesi gerekebileceğini düşündüm. fabrika işlevleriyle kurucuların nasıl değiştirileceği örnek ve tutarlılık örneklerde gerekli olduğunu düşündüm. Her neyse, cevap yeterince bilgilendirici. Bu sadece yükseltmek istediğim bir nokta, cevabın kalitesini hiçbir şekilde düşürmemek değil. - Bharat Khatri
Benim için Fabrika fonksiyonlarının en büyük avantajı daha iyi olmanızdır. kapsülleme ve veri gizleme Bazı uygulamalarda yararlı olabilir. Her örnek özellik ve yöntemlerin kullanıcılar tarafından yapılması ve kullanıcılar tarafından kolayca değiştirilebilmesi konusunda herhangi bir sorun yoksa, bazı insanlar gibi "yeni" anahtar kelimeyi beğenmediğiniz sürece Yapıcı işlevinin daha uygun olduğunu tahmin ediyorum. - devius
@Federico - fabrika yöntemleri sadece düz bir nesneyi döndürmek zorunda kalmaz. Kullanabilirler new dahili olarak veya kullanım Object.create() Belirli bir prototip ile bir nesne oluşturmak için. - nnnnnn


Kurucuları kullanmanın yararları

  • Çoğu kitap, kurucuları kullanmanızı ve new

  • this yeni nesneyi ifade eder

  • Bazı insanlar yolu sever var myFoo = new Foo(); okur.

Dezavantajları

  • Aramanın ayrıntıları çağrı API'sine sızdı ( new gereksinim), bu nedenle tüm arayanlar yapıcı uygulamasına sıkı sıkıya bağlıdır. Fabrikanın ek esnekliğine ihtiyacınız olursa, tüm arayanları (kuraldan ziyade istisnai durum) kabul etmelisiniz.

  • unutma new Böyle yaygın bir hatadır, kurucunun doğru bir şekilde çağrıldığından emin olmak için bir kazan denetimi eklemeyi kesinlikle düşünmelisiniz ( if (!(this instanceof Foo)) { return new Foo() } ). DÜZENLEME: ES6'dan beri (ES2015) unutamazsınız new Birlikte class kurucu veya kurucu bir hata atacaktır.

  • Yaparsan instanceof kontrol edin, belirsiz olup olmadığını belirsizliğe bırakır new gerekli. Benim düşüncemde olmamalı. Etkili olarak kısa devre yaptınız new gereksinimi, yani # 1 dezavantajını silebilirsiniz. Ama sonra Sadece isminde bir fabrika işlevine sahipsinek boilerplate, büyük harf ve daha az esnek this bağlamı.

Yapıcılar Açık / Kapalı Prensibini kırar

Ama benim asıl kaygım, açık / kapalı ilkeyi ihlal etmesi. Bir kurucuyu dışa aktarmaya başlarsınız, kullanıcılar kurucuyu kullanmaya başlarlar, daha sonra bir fabrikanın esnekliğine ihtiyaç duyduğunuzu fark ettiğiniz yoldan aşağıya inersiniz (örneğin, uygulamayı nesne havuzlarını kullanmak için değiştirmek veya yürütme bağlamları arasında örnek oluşturmak için) prototip OO kullanarak daha fazla kalıtım esnekliği var.

Yine de sıkışmışsın. Yapıcınızı çağıran tüm kodu kırmadan değişikliği yapamazsınız. new. Örneğin, performans artışı için nesne havuzlarını kullanmaya başlayamazsınız.

Ayrıca, kurucuları kullanarak bir aldatmaca verir instanceof Bu, yürütme bağlamlarında çalışmaz ve kurucunuzun prototipi değiştirilirse çalışmaz. Geri dönmeye başlarsanız başarısız olur this kurucunuzdan ve sonra yapıcınızdaki fabrika benzeri davranışı etkinleştirmek için yapmanız gereken keyfi bir nesneyi dışa aktarmaya geçin.

Fabrikaları kullanmanın yararları

  • Daha az kod - boilerplate gerekli.

  • Herhangi bir rastgele nesneyi döndürebilir ve herhangi bir keyfi prototip kullanabilir ve aynı API'yi uygulayan çeşitli nesneler oluşturmak için size daha fazla esneklik kazandırabilirsiniz. Örneğin, hem HTML5 hem de flash oynatıcıların örneklerini oluşturabilen bir medya oynatıcı veya DOM olaylarını veya web soket olaylarını yayabilecek bir etkinlik kütüphanesi. Fabrikalar, aynı zamanda, uygulama bağlamları boyunca nesneleri başlatabilir, nesne havuzlarından yararlanabilir ve daha esnek prototipli kalıtım modellerine olanak tanır.

  • Bir fabrikadan kurgana dönüşme gereği duymazsınız, bu nedenle yeniden düzenleme hiçbir zaman bir sorun olmayacaktır.

  • Kullanım hakkında hiçbir belirsizlik new. Yapma. (Yapacak this kötü davranmak, sonraki noktaya bakınız).

  • this normalde olduğu gibi davranır - böylece ana nesneye erişmek için kullanabilirsiniz (örneğin, player.create(), this ifade eder playerTıpkı başka herhangi bir yöntem çağrısı gibi. call ve apply ayrıca atayın this, beklenildiği gibi. Prototipleri ana nesnede depolarsanız, bu işlevler dinamik olarak takas etmenin ve nesne eşleştirmeniz için çok esnek bir polimorfizme olanak tanımanın harika bir yolu olabilir.

  • Büyük harf kullanıp kullanmama konusunda bir belirsizlik yok. Yapma. Lint araçları şikayet edecek ve sonra kullanmayı denemek için cazip olacaksınız newve sonra yukarıda açıklanan faydayı geri alırsınız.

  • Bazı insanlar yolu sever var myFoo = foo(); veya var myFoo = foo.create(); okur.

Dezavantajları

  • new beklenildiği gibi davranmaz (yukarıya bakın). Çözüm: kullanma.

  • this yeni nesneye başvurmaz (eğer yapıcı nokta notasyonu veya köşeli ayraç notasyonu ile çağrılırsa, ör. foo.bar () - this ifade eder foo - Diğer tüm JavaScript metotları gibi - faydaları gör).


92
2018-01-05 14:43



Hangi anlamda, kurucuların arayanları uygulamalarına sıkı sıkıya bağladıkları anlamına mı geliyor? Kurucu argümanları ile ilgili olarak, bunların kullanılması için fabrika işlevine bile geçirilmesi ve uygun kurucuyu çağırması gerekir. - Bharat Khatri
Açık / Kapalı'nın ihlali ile ilgili olarak: Bağımlılık enjeksiyonunun tamamı bu değil midir? A'nın B'ye ihtiyacı varsa, A yeni B () veya A BFactory.create () çağrısını çağırırsa, her ikisi de birleştirme işlemini başlatır. Öte yandan, kompozisyon kökü içinde A'nın bir örneğini verirseniz, A'nın B'nin nasıl örneklendiği hakkında hiçbir şey bilmesi gerekmez. Kurucuların ve fabrikaların kullanımlarının olduğunu hissediyorum; Kurucular basit bir örnekleme için, daha karmaşık bir örnekleme için fabrikalar. Ancak her iki durumda da bağımlılıklarınızı enjekte etmek akıllıcadır. - Stefan Billiet
DI enjekte etme durumu için iyidir: yapılandırma, etki alanı nesneleri vb. Diğer her şey için çok fazla. - Eric Elliott
Yaygara gerektiren şey new Açık / kapalı ilkeyi ihlal eder. Görmek medium.com/javascript-scene/... Bu yorumlardan çok daha büyük bir tartışma için izin verir. - Eric Elliott
Çünkü herhangi bir işlev yeni bir nesneyi JavaScript’e dönüştürebilir ve pek çoğunu new anahtar kelime, ben buna inanmıyorum new anahtar kelime aslında herhangi bir ek okunabilirlik sağlar. IMO, arayanların daha fazla yazmasını sağlamak için çemberin içinden atlamak aptalca görünüyor. - Eric Elliott


Bir kurucu, onu çağırdığınız sınıfın bir örneğini döndürür. Bir fabrika işlevi herhangi bir şey döndürebilir. Rasgele değerler döndürmeniz gerektiğinde veya bir sınıfın büyük bir kurulum süreci olduğunda bir fabrika işlevini kullanırsınız.


34
2018-01-02 08:24



+1 güzel ve özlü - Vinayak Garg


Fabrikalar "her zaman" daha iyidir. Nesne yönelimli dilleri kullanırken o zaman

  1. sözleşmeye karar vermek (yöntemler ve yapacakları)
  2. Bu yöntemleri ortaya çıkaran arayüzler oluşturun (javascript'te arayüzünüz yoktur, bu yüzden uygulamayı kontrol etmenin bir yolunu bulmanız gerekir)
  3. Gereken her arabirimin bir uygulamasını döndüren bir fabrika oluşturun.

Uygulamalar (yeni ile oluşturulan gerçek nesneler) fabrika kullanıcısına / tüketicisine maruz kalmaz. Bu, fabrika geliştiricisinin sözleşmeyi bozmadığı sürece yeni uygulamalar geliştirip geliştirebileceği anlamına gelir ... ve fabrika tüketicisinin kodlarını değiştirmek zorunda kalmadan yeni API'den faydalanmasını sağlar ... Yeni ve "yeni" bir uygulama kullansalar da, "yeni" uygulamayı kullanmak için "yeni" yi kullanan her çizgiyi değiştirmeli ve değiştirmeliler.

Fabrikalar - her şeyden daha iyi - bahar çerçevesi tamamen bu fikir etrafında inşa edilmiştir.


1
2017-07-09 11:14





Fabrikalar bir soyutlama katmanıdır ve tüm soyutlamalar gibi, karmaşıklık içinde bir. Fabrikanın belirli bir API için ne olduğunu belirleyen fabrika tabanlı bir API ile karşılaşıldığında API tüketicisi için zor olabilir. Kurucular ile keşfedilebilirlik önemsizdir.

Klişeler ve fabrikalar arasında karar verirken, karmaşıklığın fayda ile doğrulanıp kaynaklanmadığına karar vermelisiniz.

Javascript kurucularının, bu ya da tanımlanmamış başka bir şey döndürerek keyfi fabrikalar olabileceğine dikkat çekmek gerekir. Yani js'de keşfedilebilir API ve nesne havuzlama / önbellekleme - her iki dünyanın en iyisini elde edebilirsiniz.


0
2018-04-07 02:52



JavaScript'te, kurucuları kullanma maliyeti fabrika kullanma maliyetinden daha yüksektir, çünkü JS'deki herhangi bir işlev yeni bir nesne döndürür. Yapıcılar karmaşıklığı şöyle ekliyor: Zorunlu new, Davranışını değiştirmek this, Dönüş değeri değiştirme, Prototip ref bağlanması, Etkinleştirme instanceof (Bu amaç için kullanılmalı ve kullanılmamalıdır). Görünüşte, bunların hepsi "özellikler" dir. Pratikte kod kalitesine zarar veriyorlar. - Eric Elliott