Statik sınıf yerine tekli kalıbı ne zaman kullanmalısınız? [kapalı]


85

Statik bir sınıf ile tekli kullanım arasında karar verirken tasarım hususlarını adlandırın . Bunu yaparken, ikisini karşılaştırmak zorunda kalıyorsunuz, bu nedenle bulabileceğiniz karşıtlıklar da düşünce sürecinizi göstermede yararlıdır! Ayrıca, her görüşmeci açıklayıcı örnekler görmeyi sever. :)


bir java sınıfı, bir iç sınıfı olmadığı sürece statik olamaz
Harshana

1
Nesnenin durumu önemliyse, tekli kullanın, aksi takdirde statik bir sınıf kullanın.
Levent Divilioglu

Yanıtlar:


80
  • Singleton'lar arayüzler uygulayabilir ve diğer sınıflardan miras alabilir.
  • Singletonlar tembel yüklenebilir. Sadece gerçekten ihtiyaç duyulduğunda. Başlatma işlemi pahalı kaynak yükleme veya veritabanı bağlantıları içeriyorsa bu çok kullanışlıdır.
  • Singleton'lar gerçek bir nesne sunar.
  • Tekli tonlar bir fabrikaya genişletilebilir. Perde arkasındaki nesne yönetimi soyuttur, bu nedenle bakımı daha kolaydır ve daha iyi kod sağlar.

2
Bu bağlantıya da bir göz atın: codeofdoom.com/wordpress/2008/04/20/…
Amit

4
"Singletons can be lazy loading" - C # 'da, statik yapıcı yalnızca statik bir üyeye ilk başvurulduğunda çağrılır. PHP'de, otomatik yüklemeyi yalnızca sınıf ilk kullanıldığında çalıştırmak için kullanabilirsiniz.
mpen

Java statik başlatmaları da tembeldir. Singletons için puan yok.
MikeFHay

13

"İkisinden de kaçının" nasıl olur? Tekli ve statik sınıflar:

  • Küresel durumu tanıtabilir
  • Diğer birçok sınıfa sıkı sıkıya bağlanın
  • Bağımlılıkları gizle
  • Tek başına birim test sınıflarını zorlaştırabilir

Bunun yerine, Bağımlılık Enjeksiyonu ve Kontrol Kabı kitaplıklarının Tersine Çevrilmesi konusuna bakın . IoC kitaplıklarının birçoğu sizin için ömür boyu yönetimi gerçekleştirecektir.

(Her zaman olduğu gibi, statik matematik sınıfları ve C # genişletme yöntemleri gibi istisnalar vardır.)


1
Küçük nitler: tekli sınıflar, bağımlılık ekleme teknikleriyle uyumludur (bunları yalnızca bağımlı sınıflarına enjekte edin ve hiçbir şeyi sabit kodlamalarına gerek yoktur) - bu, tek başına alay ve teste izin verir. Ayrıca, platform genelinde sınırlı olduğu bilinen kaynakları yönetmek için geçerli bir tasarım modelidir. (Klasik örneği hiçbir çekişme yönetimi sahip yazıcılar içindir.)
cdleary

@cdleary - kabul edildi; ancak klasik uygulama genellikle kod tabanı boyunca Singleton.getInstance () 'ı bırakır. Kaynakları, önbellekleri vb. Yönetmek için "Singletons", POCO'lar / POJO'lar ve ömür boyu yönetimi destekleyen IoC Container çerçeveleri ile uygulanabilir (türü kapsayıcı ömrü olarak kaydedin ve her çözüm aynı örneği alacaktır).
TrueWill

9
Singleton'larınıza düzgün bir cenaze töreni yapmak istiyorsanız, singletonfuneralservice.com'a
TrueWill

1
Hide Dependenciesbu noktada küçük sideinfo: Sen kullanarak örneğin Kontrol desen inversiyon uygulayabilir Ninject . Bu, bir türün yalnızca bir örneğini bir türüne bağlayarak kullanmanıza izin verir SingletonScope; bu, her zaman aynı örneği enjekte edeceği , ancak sınıfın tekli olmayacağı anlamına gelir .
LuckyLikey

8

Tek farkın sözdizimi olduğunu iddia ediyorum: MySingleton.Current.Whatever () - MySingleton.Whatever (). David'in bahsettiği gibi, her iki durumda da sonuçta "durağan" dır.


DÜZENLEME: Gömme tugayı digg'den geldi ... her neyse, bir tekil gerektiren bir dava düşündüm. Statik sınıflar bir temel sınıftan miras alamaz veya bir arabirim uygulayamaz (en azından .Net'te yapamazlar). Dolayısıyla, bu işlevselliğe ihtiyacınız varsa, bir tekli kullanmalısınız.


7

Bu konuyla ilgili en sevdiğim tartışmalardan biri burada (orijinal site kapalı, şimdi İnternet Arşivi Wayback Machine ile bağlantılı .)

Bir Singleton'un esneklik avantajlarını özetlemek gerekirse:

  • bir Singleton kolayca fabrikaya dönüştürülebilir
  • bir Singleton, farklı alt sınıfları döndürmek için kolayca değiştirilebilir
  • bu daha bakımlı bir uygulama ile sonuçlanabilir

5

Statik değişkenler içeren statik bir sınıf, biraz hacklemektir.

/**
 * Grotty static semaphore
 **/
 public static class Ugly {

   private static int count;

   public synchronized static void increment(){
        count++;
   }

   public synchronized static void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized static boolean isClear(){
         return count==0;    

    }
   }

Gerçek bir örneğe sahip bir singleton daha iyidir.

/**
 * Grotty static semaphore
 **/
 public static class LessUgly {
   private static LessUgly instance;

   private int count;

   private LessUgly(){
   }

   public static synchronized getInstance(){
     if( instance==null){
        instance = new LessUgly();
     }
     return instance;
   }
   public synchronized void increment(){
        count++;
   }

   public synchronized void decrement(){
        count--;
        if( count<0 ) {
            count=0;
        }
   }

   public synchronized boolean isClear(){
         return count==0;    

    }
   }

Eyalet YALNIZCA durumdadır.

Böylece, daha sonra havuzlama, iş parçacığı yerel örnekler vb. Yapmak için tekil değiştirilebilir. Ve zaten yazılmış kodların hiçbirinin fayda sağlamak için değiştirilmesi gerekmez.

public static class LessUgly {
       private static Hashtable<String,LessUgly> session;
       private static FIFO<LessUgly> freePool = new FIFO<LessUgly>();
       private static final POOL_SIZE=5;
       private int count;

       private LessUgly(){
       }

       public static synchronized getInstance(){
         if( session==null){
            session = new Hashtable<String,LessUgly>(POOL_SIZE);
            for( int i=0; i < POOL_SIZE; i++){
               LessUgly instance = new LessUgly();  
               freePool.add( instance)
            }
         }
         LessUgly instance = session.get( Session.getSessionID());
         if( instance == null){
            instance = freePool.read();
         }
         if( instance==null){
             // TODO search sessions for expired ones. Return spares to the freePool. 
             //FIXME took too long to write example in blog editor.
         }
         return instance;
       }     

Statik bir sınıfla benzer bir şey yapmak mümkündür, ancak dolaylı gönderimde çağrı başına ek yük olacaktır.

Örneği alıp argüman olarak bir işleve geçirebilirsiniz. Bu, kodun "doğru" tektona yönlendirilmesini sağlar. Siz istemeyene kadar bunlardan sadece birine ihtiyacınız olacağını biliyoruz.

En büyük fayda, durum bilgisi olan tekillerin iş parçacığı güvenli hale getirilebilmesidir, oysa statik bir sınıf, siz onu gizli bir tekli olarak değiştirmedikçe bunu yapamaz.


4

Bir singleton'u bir servis gibi düşünün. Belirli bir işlevsellik kümesi sağlayan bir nesnedir. Örneğin

ObjectFactory.getInstance().makeObject();

Nesne fabrikası, belirli bir hizmeti gerçekleştiren bir nesnedir.

Buna karşılık, statik yöntemlerle dolu bir sınıf, gerçekleştirmek isteyebileceğiniz, ilişkili bir grup (Sınıf) içinde organize edilmiş bir eylemler koleksiyonudur. Örneğin

StringUtils.reverseString("Hello");
StringUtils.concat("Hello", "World");

Buradaki StringUtils örneği, her yere uygulanabilen bir işlevsellik koleksiyonudur. Tekli fabrika nesnesi, gerektiğinde oluşturulabilen ve etrafta dolaşılabilen açık bir sorumluluğa sahip belirli bir nesne türüdür.


4

Statik sınıflar çalışma zamanında başlatılır. Bu zaman alıcı olabilir. Singletons yalnızca ihtiyaç duyulduğunda somutlaştırılabilir.


13
Tekil komutlar da çalışma zamanında örneklenir ...
özyinelemeli

1
@ recursive: Singleton somutlaştırma kontrol edilebilir.
Nikit Batale

3
belki de daha iyi bir kelime ilklendirme olabilir (somutlaştırmadan ziyade)
Marlon

3

Tekil sınıflar, statik sınıflarla aynı şekilde kullanılmamalıdır. Aslında,

MyStaticClass.GetInstance().DoSomething();

esasen aynıdır

MyStaticClass.DoSomething();

Aslında yapmanız gereken , singleton'a başka bir nesne gibi davranmaktır . Bir hizmet singleton türünün bir örneğini gerektiriyorsa, bu örneği yapıcıda iletin:

var svc = new MyComplexServce(MyStaticClass.GetInstance());

Servis, nesnenin bir tekil olduğunun farkında olmamalı ve nesneyi sadece bir nesne olarak ele almalıdır.

Nesne, işleri kolaylaştıracaksa, bir uygulama ayrıntısı olarak ve genel konfigürasyonun bir yönü olarak, bir tekil olarak kesinlikle uygulanabilir. Ancak nesneyi kullanan şeyler, nesnenin tekli olup olmadığını bilmek zorunda olmamalıdır.


2

"Statik sınıf" derken, yalnızca statik değişkenlere sahip bir sınıfı kastediyorsanız, o zaman bunlar aslında durumu koruyabilirler. Anladığım kadarıyla tek fark, bu şeye nasıl eriştiğinizdir. Örneğin:

MySingleton().getInstance().doSomething();

karşı

MySingleton.doSomething();

MySingleton'ın iç kısımları açıkça aralarında farklı olacaktır, ancak iş parçacığı güvenliği sorunları bir yana, her ikisi de müşteri kodu açısından aynı şeyi yapacaklardır.


2
Tekillerin kendileri birer nesnedir -> bağımsız değişken olarak iletilebilirler.
Christian Klauser

2

Tekli desen genellikle, birden çok iş parçacığının aynı anda verilere erişebildiği durumlarda bağımsız veya statik verilere hizmet vermek için kullanılır. Durum kodları bir örnek olabilir.


1

Singleton'lar asla kullanılmamalıdır (değişken durumu olmayan bir sınıfı tek ton olarak düşünmediğiniz sürece). "Statik sınıflar", iş parçacığı güvenli önbellekler ve benzerleri dışında, değiştirilebilir bir duruma sahip olmamalıdır.

Hemen hemen herhangi bir singleton örneği nasıl yapılmayacağını gösterir.


4
Donanım kaynaklarını kontrol eden yönetici sınıfları ne olacak? Peki ya günlük dosyası sınıfları?
RJFalconer

0

Bir singleton elden çıkarabileceğiniz bir şeyse, ondan sonra temizlemek için, sınırlı bir kaynak olduğunda (yani sadece 1 tanesine) her zaman ihtiyacınız olmadığını ve bir tür belleğiniz olduğunu düşünebilirsiniz. tahsis edildiğinde kaynak maliyeti.

Temizleme kodu, statik durum alanları içeren statik bir sınıfın aksine, bir tekiniz olduğunda daha doğal görünür.

Bununla birlikte, kod her iki şekilde de aynı görünecektir, bu yüzden sormak için daha spesifik nedenleriniz varsa, belki de ayrıntıya girmelisiniz.


0

İkisi oldukça benzer olabilir, ancak gerçek Singleton'un kendisinin somutlaştırılması (bir kez verilir) ve sonra hizmet edilmesi gerektiğini unutmayın . Örneğini döndüren bir PHP veritabanı sınıfı mysqligerçekte bir Singleton değildir (bazılarının dediği gibi), çünkü örneğe statik bir üye olarak sahip olan sınıfın bir örneğini değil, başka bir sınıfın bir örneğini döndürür.

Dolayısıyla, kodunuzda yalnızca bir örneğine izin vermeyi planladığınız yeni bir sınıf yazıyorsanız, bunu bir Singleton olarak da yazabilirsiniz. Bunu bir sade jane sınıfı yazmak ve tek örnekleme gereksinimini kolaylaştırmak için ona ekleme yapmak olarak düşünün. Değiştiremeyeceğiniz başka birinin sınıfını kullanıyorsanız (gibi mysqli), statik bir sınıf kullanmalısınız (tanımının önüne anahtar kelime koymasanız bile).


0

Tekil sesler daha esnektir ve bu, Örnek yönteminin bazı bağlama dayalı olarak Singleton türünün farklı somut alt sınıflarını döndürmesini istediğiniz durumlarda yararlı olabilir.


0

Statik sınıflar bağımsız değişken olarak aktarılamaz; bir singleton örnekleri olabilir. Diğer yanıtlarda belirtildiği gibi, statik sınıflarla ilgili konuları izleyin.

rp


0

Bir singleton bir kurucu ve yıkıcıya sahip olabilir. Dilinize bağlı olarak, kurucu, tekliğiniz ilk kez kullanıldığında otomatik olarak çağrılabilir veya tekliğiniz hiç kullanılmıyorsa hiçbir zaman çağrılabilir. Statik bir sınıfın böyle bir otomatik başlatması olmaz.

Tekil bir nesneye bir referans elde edildiğinde, diğer herhangi bir nesne gibi kullanılabilir. Müşteri kodunun, singleton'a bir referans daha önce saklanmışsa, bir singleton kullandığını bilmesine gerek olmayabilir:

Foo foo = Foo.getInstance();
doSomeWork(foo); // doSomeWork wont even know Foo is a singleton

Bu, IoC gibi gerçek bir model lehine Singleton modelini terk etmeyi seçtiğinizde işleri kolaylaştırır.


0

Arama tabloları gibi, yapabiliyorsanız derleme zamanında hesaplayacağınız bir şeyi çalışma zamanında hesaplamanız gerektiğinde tekli kalıbı kullanın.


0

Bence, Singleton'ın statik sınıftan daha anlamlı olacağı bir yer, maliyetli kaynaklardan oluşan bir havuz (veritabanı bağlantıları gibi) oluşturmanız gerektiğinde. Hiç kimse onları kullanmıyorsa havuzu oluşturmakla ilgilenmezsiniz (statik sınıf, sınıf yüklendiğinde maliyetli işi yaptığınız anlamına gelir).


0

Verileri verimli bir şekilde önbelleğe almaya zorlamak istiyorsanız, bir tekil de iyi bir fikirdir. örneğin, bir xml belgesindeki tanımları arayan bir sınıfım var. Belgenin ayrıştırılması biraz zaman alabileceğinden, bir tanım önbelleği ayarlıyorum (outOfmemeoryErrors'ı önlemek için SoftReferences kullanıyorum). İstenilen tanım önbellekte değilse, pahalı xml ayrıştırmasını yaparım. Aksi takdirde önbellekten bir kopya döndürürüm. Birden fazla önbelleğe sahip olmak, aynı tanımı birden çok kez yüklemem gerekebileceği anlamına geldiğinden, statik bir önbelleğe ihtiyacım var. Bu sınıfı bir singleton olarak uygulamayı seçiyorum, böylece sınıfı yalnızca normal (statik olmayan) veri üyelerini kullanarak yazabilirim. Bu, herhangi bir nedenle (serileştirme, birim testi, vb.) İhtiyacım olursa, sınıfın somutlaştırmasını oluşturmama izin veriyor.


0

Singleton, daha önce de belirtildiği gibi bir hizmet gibidir. Pro, esnekliğidir. Statik, pekala, Singleton'ı uygulamak için bazı statik parçalara ihtiyacınız var.

Singleton, gerçek nesnenin somutlaştırılmasıyla ilgilenecek bir koda sahiptir ve bu, yarış sorunlarıyla karşılaşırsanız çok yardımcı olabilir. Statik bir çözümde, birden çok kod konumunda yarış problemleriyle uğraşmanız gerekebilir.

Bununla birlikte, Singleton'ın bazı statik değişkenlerle yapılandırılabilmesi gibi, onu 'goto' ile karşılaştırabilirsiniz. Diğer yapıları inşa etmek için oldukça yararlı olabilir, ancak onu nasıl kullanacağınızı gerçekten bilmeniz ve 'aşırı' kullanmamalısınız. Bu nedenle genel tavsiye, Singleton'a bağlı kalmak ve gerekirse statik kullanmaktır.

ayrıca diğer gönderiyi de kontrol edin: Neden tekil uygulama yerine statik bir sınıf seçmelisiniz?


0

bakın bu

özet:

a. Takip edebileceğiniz kolay bir temel kural, durumu sürdürmesi gerekmiyorsa, bir Statik sınıf kullanabilirsiniz, aksi takdirde bir Singleton kullanmanız gerekir.

b. Özellikle “ağır” bir nesne ise bir Singleton kullanın. Nesneniz büyükse ve makul miktarda bellek kullanıyorsa, çok sayıda n / w çağrısı (bağlantı havuzu) ..vb. Birden çok kez somutlaştırılmayacağından emin olmak için. Bir Singleton sınıfı, böyle bir durumun meydana gelmesini önlemeye yardımcı olacaktır


-1

Tek sınıfın devlete ihtiyacı olduğunda. Singletonlar global bir durumu korurlar, statik sınıflar yapmaz.

Örneğin, bir kayıt sınıfının etrafında bir yardımcı yapmak: Değiştirilebilir kovanınız varsa (HKey Geçerli Kullanıcıya karşı HKEY Yerel Makine) şunları yapabilirsiniz:

RegistryEditor editor = RegistryEditor.GetInstance();
editor.Hive = LocalMachine

Artık bu tekil kişiye yapılacak diğer çağrılar Yerel Makine kovanında çalışacaktır. Aksi takdirde, statik bir sınıf kullanarak, Yerel Makine kovanını her seferinde belirtmeniz veya gibi bir yönteme sahip olmanız gerekir ReadSubkeyFromLocalMachine.


1
Bu şekilde bir Singleton kullanılmasına karşı çıkıyorum ... Durumları bekletmek çok tehlikelidir, çünkü bir sonraki arayan, kovanı ayarlamayı ve yanlış kovandaki kayıt defterine yazmayı unutabilir ... :-( Bu Muhtemelen insanları Singletonların kötü olduğunu düşündüren bir kötüye kullanım örneği.
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.