Statik fabrika yöntemleri nelerdir?


261

"Statik fabrika" yöntemi nedir?


Alternatif bir statik fabrika yöntemi bağımlılık enjeksiyonu kullanmaktır.
CMCDragonkai

1
@ThangPham Jason Owen'ın cevabı kusurludur, çünkü aslında bahsettiği statik fabrika yöntemi modelinden çok farklı olan Fabrika Metodu deseni hakkında konuştuğunu iddia ediyor. Bu nedenle, asıl soruyu cevaplamak için iyi bir iş çıkarsa da, mevcut durumunda kabul edilebileceğini düşünmüyorum, çünkü ilgisiz bir desen getiriyor ve iki desen arasındaki fark hakkında inanılmaz derecede kafa karışıklığını artırıyor.
Theodore Murdock

@CMCDragonkai Bağımlılık enjeksiyonu ve statik fabrika farklı olduğunu düşünüyorum. Enjekte edilecek bağımlılıkların başlatılması için bağımlılık enjeksiyonu durumunda bile statik fabrika gerekebilir.
Karan Khanna

Yanıtlar:


126

Kaynak yoğun oldukları için veritabanı bağlantılarına doğrudan erişim sağlamaktan kaçınırız. Bu nedenle getDbConnection, sınırın altında olduğumuzda bağlantı oluşturan statik bir fabrika yöntemi kullanıyoruz . Aksi takdirde, "yedek" bir bağlantı sağlamaya çalışır, yoksa bir istisna ile başarısız olur.

public class DbConnection{
   private static final int MAX_CONNS = 100;
   private static int totalConnections = 0;

   private static Set<DbConnection> availableConnections = new HashSet<DbConnection>();

   private DbConnection(){
     // ...
     totalConnections++;
   }

   public static DbConnection getDbConnection(){

     if(totalConnections < MAX_CONNS){
       return new DbConnection();

     }else if(availableConnections.size() > 0){
         DbConnection dbc = availableConnections.iterator().next();
         availableConnections.remove(dbc);
         return dbc;

     }else {
         throw new NoDbConnections();
     }
   }

   public static void returnDbConnection(DbConnection dbc){
     availableConnections.add(dbc);
     //...
   }
}

doğru anlıyorsam, returnDbConnection (DbConnection db) yöntemine availableConnections.add (db) ekleyebilir misiniz?
Haifeng Zhang

@haifzhan, tam olarak amaçlanmamış, ama tamam.
Matthew Flaschen

@MatthewFlaschen ayrıca bağlantı geri verilirken totalConnections azaltılmalı mı?
yuvarlanan taş

@Sridhar, hayır, dolaşan numara değil, var olan bağlantı sayısı (MAX_CONNS'dan fazla oluşturulmaması için izlenir).
Matthew Flaschen

@MatthewFlaschen you yöntemi eğer DbConnection kapatılabilir ise sonarcube tarafından engelleyici-hata olarak yakalanacaktır.
Awan Biru

477

Statik fabrika yöntemi desen kapsülü nesne oluşturma için bir yoldur. Bir fabrika yöntemiyle olmadan, sadece sınıfının çağırır yapıcı doğrudan: Foo x = new Foo(). Bu desen ile, yerine fabrika yöntemini çağırır: Foo x = Foo.create(). Yapıcılar özel olarak işaretlenir, bu nedenle sınıfın dışında çağrılamazlar ve fabrika yöntemi, staticönce bir nesneye sahip olmadan çağrılabilecek şekilde işaretlenir .

Bu modelin birkaç avantajı vardır. Birincisi, fabrika birçok alt sınıftan (veya bir arayüzün uygulayıcılarından) seçim yapabilir ve bunu iade edebilir. Bu şekilde arayan, potansiyel olarak karmaşık bir sınıf hiyerarşisini bilmek veya anlamak zorunda kalmadan parametreler aracılığıyla istenen davranışı belirleyebilir.

Bir diğer avantaj, Matthew ve James'in belirttiği gibi, bağlantılar gibi sınırlı bir kaynağa erişimi kontrol etmektir. Bu , yeniden kullanılabilir nesnelerin havuzlarını uygulamanın bir yolu - bir nesneyi inşa etmek, kullanmak ve yıkmak yerine, inşaat ve yıkım pahalı süreçlerse, bunları bir kez inşa etmek ve geri dönüştürmek daha mantıklı olabilir. Fabrika yöntemi, varsa, kullanılmayan, somutlaştırılmış bir nesneyi döndürebilir veya nesne sayısı daha düşük bir eşiğin altındaysa bir tane oluşturabilir veya nullüst eşiğin üstünde ise bir istisna veya dönüş atabilir .

Wikipedia'daki makaleye göre, çoklu fabrika yöntemleri de benzer argüman türlerinin farklı yorumlarına izin verir. Normalde kurucu sınıfla aynı ada sahiptir, yani belirli bir imzası olan yalnızca bir kurucuya sahip olabilirsiniz . Fabrikalar çok kısıtlı değildir, yani aynı argüman türlerini kabul eden iki farklı yönteminiz olabilir:

Coordinate c = Coordinate.createFromCartesian(double x, double y)

ve

Coordinate c = Coordinate.createFromPolar(double distance, double angle)

Bu, Rasmus'un belirttiği gibi, okunabilirliği artırmak için de kullanılabilir.


32
Statik bir fabrika yönteminin, Tasarım Desenlerindeki Fabrika Metodu deseni ile aynı olmadığını unutmayın [Gamma95, s. 107]. Bu öğede açıklanan statik fabrika yönteminin Tasarım Desenlerinde doğrudan eşdeğeri yoktur.
Josh Sunshine

Bu cevabın benim için getirisi, poolable nesnelerin referansıdır. Bu tam olarak fabrika yöntem kalıbını kullanıyorum. Bir nesnenin yaşam döngüsünü denetlemeye yardımcı olmak için fabrika yöntemleri sağlanmıştır: "create", havuzdan bir nesne çeker veya havuz boşsa yeni bir örnek oluşturur, "destroy", ileride yeniden kullanılmak üzere havuza geri gönderir.
MutantXenu

2
Bu yazıda "fabrika yöntemi kalıbı" dediğiniz her yerde gerçekten "statik fabrika yöntemi kalıbı" kullanıyor olmalısınız, yanlış terimi kullanıyorsunuz. Ayrıca, bahsettiğiniz modelden farklı bir düzende Wikipedia makalesine bağlantı veriyorsunuz. Fabrika Metodu deseni muhtemelen "Fabrika Arayüzü" deseni olarak adlandırılmalıdır, çünkü bir fabrika nesnesini kabul ederek tek bir algoritmanın hem üretim hem de arayüz ile çalışmasını sağlamak için bir fabrika arayüzü uygulayan birkaç fabrika nesnesinin kullanılmasını içerir. istenilen alt sınıfı üretebilir.
Theodore Murdock

8
@TheodoreMurdock ile hemfikirim. Yanlış terimi kullanıyorsunuz. Bahsettiğiniz şey Joshua Bloch'un "Statik Fabrika Yöntemi" dir ancak GoF'un "Fabrika Yöntem Kalıbı" terimini kullanırsınız. Lütfen diğer kişilerin yanlış anlamaması için düzenleyin.
emeraldhieu

1
Yapıcı özel olmak zorunda değildir. Bir sınıf hem kamu statik fabrika yöntemleri hem de kurucuları sağlayabilir.
Kevin

171

NOT! " Statik fabrika yöntemi , Fabrika Yöntemi ile aynı DEĞİLDİR " (c) Etkili Java, Joshua Bloch.

Fabrika Yöntemi: "Nesne oluşturmak için bir arabirim tanımlayın, ancak arabirimi uygulayan sınıfların hangi sınıfın örnekleneceğine karar vermesine izin verin. Fabrika yöntemi, bir sınıfın alt sınıflara örnek oluşturmayı ertelemesine izin verir" (c) GoF.

"Statik fabrika yöntemi, bir sınıf örneğini döndüren statik bir yöntemdir." (c) Etkili Java, Joshua Bloch. Genellikle bu yöntem belirli bir sınıfın içindedir.

Fark:

Statik fabrika yönteminin ana fikri, nesne oluşturma üzerinde kontrol kazanmak ve bunu yapıcıdan statik yönteme devretmektir. Oluşturulacak nesnenin kararı, Soyut Fabrika'da yöntemin dışında yapılanlara benzer (ortak durumda, ancak her zaman değil). Fabrika Metodu'nun ana fikri (!), Fabrika Metodu içinde hangi sınıf örneğinin yaratılacağına dair karar vermektir. Örneğin klasik Singleton uygulaması, statik fabrika yönteminin özel bir durumudur. Yaygın olarak kullanılan statik fabrika yöntemlerine örnek:

  • değeri
  • getInstance
  • newInstance

Bana yeni A () ve A.newInstance () arasındaki farkı söyleyebilir misiniz? ve A.newInstance içinde ne yapmalıyız?
Shen,

69

Okunabilirlik statik fabrika yöntemleri ile geliştirilebilir:

Karşılaştırmak

public class Foo{
  public Foo(boolean withBar){
    //...
  }
}

//...

// What exactly does this mean?
Foo foo = new Foo(true);
// You have to lookup the documentation to be sure.
// Even if you remember that the boolean has something to do with a Bar
// you might not remember whether it specified withBar or withoutBar.

için

public class Foo{
  public static Foo createWithBar(){
    //...
  }

  public static Foo createWithoutBar(){
    //...
  }
}

// ...

// This is much easier to read!
Foo foo = Foo.createWithBar();

Bu yüzden size örnek uygulamayı denedim ama bunun nasıl çalıştığından emin değilim. Iki yöntem createWithBar ve createWithoutBar Foo sınıf içinde 2 özel yapıcı çağırmak gerekiyordu?
Essej

@Baxtex: Evet. Her biri özel bir kurucu çağırır. Belki de sadece aynı: private Foo(boolean withBar){/*..*/} public static Foo createWithBar(){return new Foo(true);} public static Foo createWithoutBar(){return new Foo(false);}
Rasmus Faber

Bence bu "ölçek" çok iyi değil. Üç veya daha fazla parametreniz varsa, bu fikri nasıl kullanabilir ve yöntem için güzel bir ad oluşturabilirsiniz?
Dherik

@Dherik: O zaman muhtemelen bunun yerine oluşturucu desenini kullanmalısınız: new FooBuilder (). WithBar (). WithoutFoo (). WithBaz (). Build ();
Rasmus Faber

21
  • kodları açıklığa kavuşturabilen kurucuların aksine adlara sahiptir.
  • her çağrı üzerine yeni bir nesne oluşturmanıza gerek yoktur - gerekirse nesneler önbelleğe alınabilir ve yeniden kullanılabilir.
  • dönüş türünün bir alt türünü döndürebilir - özellikle, uygulama sınıfı arayan tarafından bilinmeyen bir nesneyi döndürebilir. Bu, statik fabrika yöntemlerinin dönüş türü olarak arabirimleri kullanan birçok çerçevede çok değerli ve yaygın olarak kullanılan bir özelliktir.

dan http://www.javapractices.com/topic/TopicAction.do?Id=21


18

Her şey sürdürülebilirliğe kaynar. Bunu koymanın en iyi yolu, newbir nesne oluşturmak için anahtar kelimeyi her kullandığınızda, yazdığınız kodu bir uygulamaya bağlarsınız.

Fabrika kalıbı, bir nesneyi oluşturma şeklinizi nesneyle yaptığınız işlemden ayırmanızı sağlar. Tüm nesnelerinizi yapıcıları kullanarak oluşturduğunuzda, nesneyi o uygulamaya kullanan kodu kablolamaya çalışırsınız. Nesnenizi kullanan kod, o nesneye "bağımlıdır". Bu yüzeyde büyük bir şey gibi görünmeyebilir, ancak nesne değiştiğinde (kurucunun imzasını değiştirmeyi veya nesneyi alt sınıflamayı düşünün) geri dönüp her şeyi yeniden sarmanız gerekir.

Günümüzde fabrikalar, Bağımlılık Enjeksiyonu kullanmak için büyük ölçüde kenara çekildi, çünkü kendini korumak biraz zor olan çok sayıda kazan plakası koduna ihtiyaç duyuyorlar. Bağımlılık Enjeksiyonu temel olarak fabrikalara eşdeğerdir, ancak nesnelerinizin bildirim yoluyla (yapılandırma veya ek açıklamalar yoluyla) nasıl birbirine bağlanacağını belirtmenize olanak tanır.


3
Fabrikaların kurtarmaya ihtiyacı olduğunu mu söylüyorsun? ;)
John Farrell

4
Haha! Bu gün ve yaşta hepimizin bir kurtarma kullanabileceğini düşünüyorum ... :)
cwash

11

Bir sınıfın yapıcısı özelse, sınıfın dışında bir nesne oluşturamazsınız.

class Test{
 int x, y;
 private Test(){
  .......
  .......
  }
}

Yukarıdaki sınıf için onun dışında bir nesne oluşturamayız. Böylece sınıfın dışından x, y'ye erişemezsiniz. O zaman bu sınıfın kullanımı nedir?
İşte Cevap: FABRİKA yöntemi.
Yukarıdaki sınıfa aşağıdaki yöntemi ekleyin

public static Test getObject(){
  return new Test();
}

Artık bu sınıf için onun dışından bir nesne oluşturabilirsiniz. Bu şekilde ...

Test t = Test.getObject();

Bu nedenle, sınıfın nesnesini özel yapıcısını çalıştırarak döndüren statik bir yönteme FACTORY yöntemi denir
.


1
Neden buna "çözüm" diyorsunuz? Özel bir kurucu ilan etmek bir "sorun" değildir, bir tasarım örüntüsüdür.
Ojonugwa Jude Ochalifu

1
Güncellenmiş. Yine de teşekkürler
Santhosh

Merhaba @Santhosh Bir endişe var Neden özel yapıcı halka açık izin vermiyorsun? Alt sınıf oluşturmak istemiyorsanız benim için sorun değil, ancak özel kurucu yapmak istemiyorsam Static Factory Method, kamu kurucusuna göre herhangi bir yararımız var mı?
Shen

9

Bildiklerime bu yazıya biraz ışık katacağımı düşündüm. Bu tekniği yoğun olarak kullandık recent android project. Bunun yerine bir sınıfı başlatmak için creating objects using new operatorde kullanabilirsiniz static method. Kod listesi:

//instantiating a class using constructor
Vinoth vin = new Vinoth(); 

//instantiating the class using static method
Class Vinoth{
  private Vinoth(){
  }
  // factory method to instantiate the class
  public static Vinoth getInstance(){
    if(someCondition)
        return new Vinoth();
  }
}

Statik yöntemler koşullu nesne oluşturmayı destekler : Bir kurucuyu her çağırışınızda bir nesne oluşturulur ancak bunu istemeyebilirsiniz. koşulun yerine getirilmediği sürece, yalnızca yeni bir nesne oluşturmak istediğinizde bir koşulu kontrol etmek istediğinizi varsayalım.Her seferinde Vinoth'un yeni bir örneğini oluşturmayacaksınız.

Etkili Java'dan alınan başka bir örnek .

public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
}

Bu yöntem, bir boole ilkel değerini bir Boolean nesne referansına çevirir. Boolean.valueOf(boolean)Yöntem bir nesne oluşturur asla bizi göstermektedir. static factory methodsAynı nesneyi tekrarlanandan döndürme yeteneği, invocationssınıfların herhangi bir zamanda hangi örneklerin var olduğu üzerinde sıkı kontrol sahibi olmalarını sağlar.

Static factory methodsaksine constructors, dönüş türlerinden objectherhangi subtypebirini döndürebilirler. Bu esnekliğin bir uygulaması, bir API'nin sınıflarını herkese açık hale getirmeden nesneleri döndürebilmesidir. Uygulama sınıflarını bu şekilde gizlemek çok kompakt bir API'ya yol açar.

Calendar.getInstance () O yerel a bağlı oluşturur, yukarıda için harika bir örnek BuddhistCalendar, JapaneseImperialCalendarya da varsayılan teker Georgian.

Düşünebileceğim bir başka örnek Singleton pattern, kurucularınızı özel getInstanceyaptığınız, her zaman sadece bir örnek bulunduğundan emin olduğunuz kendi yöntemini oluşturduğunuz yerdir.

public class Singleton{
    //initailzed during class loading
    private static final Singleton INSTANCE = new Singleton();

    //to prevent creating another instance of Singleton
    private Singleton(){}

    public static Singleton getSingleton(){
        return INSTANCE;
    }
}

4

Fabrika yöntemi, bir nesnenin somutlaştırılmasını soyutlayan bir yöntemdir. Genel olarak fabrikalar, bazı arabirimi uygulayan yeni bir sınıf örneğine ihtiyacınız olduğunu bildiğinizde, ancak uygulayıcı sınıfı bilmediğinizde yararlıdır.

Bu, ilgili sınıfların hiyerarşileri ile çalışırken faydalıdır, bunun iyi bir örneği bir GUI araç takımıdır. Her widget'ın somut uygulamaları için yapıcıları zor kodlayabilirsiniz, ancak bir araç setini başka bir araçla değiştirmek isterseniz, değiştirmek için çok fazla yeriniz olurdu. Bir fabrika kullanarak, değiştirmeniz gereken kod miktarını azaltırsınız.


Fabrikanızın uğraştığınız somut sınıfı değil bir arayüz türü döndürdüğünü varsayarsak.
Bill Lynch

1
Bu cevap, statik fabrika yöntemleri değil , fabrika yöntemi tasarım deseni ile ilgilidir . Statik fabrika yöntemleri, bir sınıf örneğini döndüren genel bir statik yöntemdir. Daha fazla ayrıntı için Etkili Java'nın 2. Bölümüne bakın.
Josh Sunshine

4

Statik fabrikadan kaynaklanan avantajlardan biri, API'nin nesneleri sınıflarını halka açmadan döndürebilmesidir. Bu, çok kompakt bir API'ya yol açar. Java'da bu, koleksiyon API'sını çok kompakt hale getiren yaklaşık 32 sınıfı gizleyen Collections sınıfı tarafından gerçekleştirilir.


2

Statik bir fabrika yöntemi, kullanılacak somut sınıfı yalnızca bir örneğin döndürmesini sağlamak istediğinizde iyidir.

Örneğin, bir veritabanı bağlantı sınıfında, veritabanı bağlantısını oluşturmak için yalnızca bir sınıfın olmasını isteyebilirsiniz, böylece Mysql'den Oracle'a geçmeye karar verirseniz, yalnızca bir sınıftaki mantığı değiştirebilirsiniz ve uygulamanın geri kalanı yeni bağlantıyı kullanın.

Veritabanı havuzu oluşturmak istiyorsanız, bu uygulamanın geri kalanını etkilemeden de yapılabilir.

Uygulamanın geri kalanını, fabrikada yapabileceğiniz değişikliklerden korur.

Statik olmasının nedeni, bazı sınırlı kaynakların (soket bağlantılarının veya dosya tanıtıcılarının sayısı) takip edilmesini istiyorsanız, bu sınıfın kaç tanesinin geçirildiğini ve geri döndüğünü izleyebilir, böylece sınırlı kaynak.


2

Özel yapıcı ile statik fabrika yöntemlerinin avantajlarından biri (örneklerin harici olarak oluşturulmadığından emin olmak için harici sınıflar için nesne oluşturma kısıtlanmış olmalıdır), örnek kontrollü sınıflar oluşturabilmenizdir . Örnek kontrollü sınıflar , programınız sırasında iki eşit farklı örneğin ( a.equals (b) olmadığını ve eğer programınız sırasında a == b varsa ) , eşittir yöntemi yerine == operatörü ile nesnelerin eşitliğini kontrol edebileceğiniz anlamına gelir. , Etkili Java'ya göre.

Statik fabrika yöntemlerinin aynı nesneyi tekrarlanan çağrılardan döndürme yeteneği, sınıfların herhangi bir zamanda hangi örneklerin var olduğu üzerinde sıkı kontrol sahibi olmalarını sağlar. Bunu yapan sınıfların örnek kontrollü olduğu söylenir. Örnek kontrollü sınıflar yazmanın birkaç nedeni vardır. Örnek denetimi, bir sınıfın tekil (Öğe 3) veya örneklenemez (Öğe 4) olduğunu garanti etmesini sağlar. Ayrıca, değişmez bir sınıfın (Madde 15) iki eşit örneğin bulunmadığının garantisini vermesine izin verir: a.equals (b) yalnızca ve == b ise. Bir sınıf bu garantiyi verirse, istemcileri eşittir (Object) yöntemi yerine == operatörünü kullanabilir ve bu da performansın artmasına neden olabilir. Enum tipleri (Madde 30) bu garantiyi sağlar.

Etkili Java, Joshua Bloch (Madde 1, sayfa 6)


1

statik

Bir üye 'statik' anahtar kelimesi ile beyan etti.

fabrika yöntemleri

Yeni nesneler oluşturan ve döndüren yöntemler.

Java'da

Programlama dili 'statik' anlamıyla ilgilidir, ancak 'fabrika' tanımıyla ilgili değildir.


@Victor Yanıtların bağımsız değişken içermesi gerekmez. Gerçekler yeterli olmalıdır: tartışmalı ise, tartışma veya alıntı ile desteklenebilirler. Burada tartışmalı bir şey olduğunun farkında değilim.
Lorne Marquis

Cevabın çok kısa olduğu ve ilk, ikinci ve üçüncü bakışta gerçekten iyi anlaşılmadığı için, yine de sormak için OP'ye bağlı olduğunu söyledim. Boşver, fikrimi değiştirdim ve aşağı oyu kaldırmaya çalışıyorum, ama yapamam.
Victor

@Victor 'Çok kısa' tanımlayın. Bazen gerçek cevap sadece 'evet', 'hayır', 'hiçbiri' veya 'ikisi de' olur. 'Çok kısa' tamamen özneldir. Hala orijinal yorumunu anlamıyorum. Tanımları desteklemek için bağımsız değişkenlere ihtiyacınız yoktur. Tanım olarak. Cevabımı düzenledim, böylece aşağı oyu kaldırmak mümkün olacak.
Lorne Marquis

Elbette özneldir ... tüm yığın akışı cevabı özneldir, aslında yazarın bilgi düzeyi ve cevap verme isteği ile ilgilidir. Cevabınızı gerçekten anlamıyorum, belki kısaydı.
Victor

@Victor Rubbish. Gerçekler öznel değildir ve ikisi de gerçeklerden veya aksiyomlardan çıkarımsal olarak türetilebilecek konular değildir. Öte yandan 'çok kısa' sübjektif ve ben zaten buna değindim. Bu cevap aslında aynıdır bu bir sen üzerinde yorum yapmadılar. Yorumlarınız belirsizliğini koruyor.
Lorne Marquis

1

Java uygulaması, java.util.Arrays ve java.util.Collections yardımcı sınıflarını içerir. Her ikisi de statik fabrika yöntemleri , örnekleri ve nasıl kullanılacağını içerir:

Ayrıca java.lang.String sınıfı bu tür statik fabrika yöntemlerine sahiptir :

  • String.format(...), String.valueOf(..), String.copyValueOf(...)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.