it-swarm-tr.com

Singleton: Nasıl kullanılmalı

Düzenleme: Başka bir sorudan singletons hakkında birçok soru/cevap içeren bir cevap verdim: Burada singletons hakkında daha fazla bilgi:

Bu yüzden konuyu okudum Singletons: iyi tasarım veya bir koltuk değneği?
Ve tartışma hala öfkeleniyor.

Singletons'ı Tasarım Deseni (iyi ve kötü) olarak görüyorum.

Singleton'la ilgili sorun Desen değil, kullanıcılar (üzgünüm herkes). Herkes ve babaları bir tanesini doğru uygulayabileceklerini düşünüyor (ve yaptığım birçok röportajdan çoğu insan yapamıyor). Ayrıca, herkes doğru bir Singleton uygulayabileceğini düşündüğü için, Deseni kötüye kullanır ve uygun olmayan durumlarda kullanır (global değişkenleri Singletons ile değiştirerek!).

Yani cevaplanması gereken asıl sorular:

  • Singleton'u ne zaman kullanmalısınız?
  • Bir Singleton'ı doğru olarak nasıl uygularsınız?

Bu makaleye yönelik umudum, bir Singleton'ı doğru bir şekilde ne zaman (ve nasıl kullanacağımızı) kullanmanın yetkili bir kaynağını (google ve birden fazla siteyi aramak zorunda kalmak yerine) tek bir yerde toplayabileceğimizdir. Aynı zamanda, uygun olmayan bir Kullanım Listesi ve neden başarısız olduklarını ve iyi uygulamalarda zayıflıklarını açıklayan genel kötü uygulamalar listesi de uygun olacaktır.


Yani topun yuvarlanmasını sağlayın:
Elimi kaldıracağım ve kullandığım şeyin bu olduğunu ancak muhtemelen sorunları olduğunu söyleyeceğim.
“Scott Myers” ın konuyu “Effective C++” adlı kitabında ele almasını seviyorum.

Singletons kullanmak için iyi durumlar (çok fazla değil):

  • Günlük çerçeveleri
  • İplik geri dönüşüm havuzları
/*
 * C++ Singleton
 * Limitation: Single Threaded Design
 * See: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
 *      For problems associated with locking in multi threaded applications
 *
 * Limitation:
 * If you use this Singleton (A) within a destructor of another Singleton (B)
 * This Singleton (A) must be fully constructed before the constructor of (B)
 * is called.
 */
class MySingleton
{
    private:
        // Private Constructor
        MySingleton();
        // Stop the compiler generating methods of copy the object
        MySingleton(MySingleton const& copy);            // Not Implemented
        MySingleton& operator=(MySingleton const& copy); // Not Implemented

    public:
        static MySingleton& getInstance()
        {
            // The only instance
            // Guaranteed to be lazy initialized
            // Guaranteed that it will be destroyed correctly
            static MySingleton instance;
            return instance;
        }
};

TAMAM. Birlikte biraz eleştiri ve başka uygulamaları alalım.
:-)

287
Martin York

Hepiniz yanılıyorsunuz. Soruyu okuyun. Cevap:

Bir Singleton kullanın, eğer:

  • Sistemde bir türden yalnızca bir nesneye sahip olmanız gerekir.

Aşağıdaki durumlarda Singleton kullanmayın:

  • Hafızayı kaydetmek istiyorsun
  • Yeni bir şey denemek istiyorsun
  • Ne kadar bildiğini göstermek istiyorsun.
  • Çünkü herkes bunu yapıyor (Bakınız kargo kültü programcısı wikipedia'da)
  • Kullanıcı arayüzü widget'larında
  • Önbellek olması gerekiyordu
  • Dizelerde
  • Oturumlarda
  • Bütün gün gidebilirim

En iyi singleton nasıl oluşturulur:

  • Ne kadar küçük, o kadar iyi. Ben minimalistim
  • İplik emniyetli olduğundan emin olun
  • Asla boş olmadığından emin ol
  • Yalnızca bir kez oluşturulduğundan emin olun
  • Tembel veya sistem başlatma? Gereksinimlerinize kadar
  • Bazen işletim sistemi veya JVM sizin için singletonlar oluşturur (örneğin, Java içinde her sınıf tanımı bir singletondur)
  • Bir yıkıcı sağlayın veya bir şekilde kaynakları nasıl imha edeceğinizi öğrenin
  • Küçük hafıza kullan
166
Javaxpert

Singletons, iki kötü özelliği bir sınıfta birleştirebilmenizi sağlar. Bu hemen hemen her şekilde yanlış.

Bir singleton size verir:

  1. Bir nesneye genel erişim ve
  2. Bu türden birden fazla nesne bulunmadığının garantisihiçbir zaman

Bir numara basit. Globals genellikle kötüdür.gerçektenona ihtiyaç duymadıkça, nesneleri hiçbir zaman küresel olarak erişilebilir hale getirmemeliyiz.

İki numara mantıklı geliyor gibi gelebilir, ama düşünelim. En son ne zaman kazandınız * var olana atıfta bulunmak yerine yeni bir nesne mi yarattınız? Bu C++ etiketli olduğundan, o dilden bir örnek kullanalım. Kazara sık sık yazıyor musun?

_std::ostream os;
os << "hello world\n";
_

Ne zaman yazmak istersin

_std::cout << "hello world\n";
_

Tabii ki değil. Bu hataya karşı korunmaya ihtiyacımız yok çünkü bu tür bir hata gerçekleşmiyor. Olursa, doğru cevap eve gidip 12-20 saat boyunca uyumak ve daha iyi hissetmenizi sağlamaktır.

Sadece bir nesneye ihtiyaç duyulursa, sadece bir örnek oluşturun. Bir nesnenin küresel olarak erişilebilir olması gerekiyorsa, onu küresel yapın. Ancak bu, başka örnekler yaratmanın imkansız olması gerektiği anlamına gelmez.

"Sadece bir örnek mümkün" kısıtı bizi gerçekten olası hatalara karşı korumaz. Fakat buyokkodumuzu yeniden kırmak ve bakımını yapmak çok zorlaştırıyor. Çünkü sıklıklalaterbirden fazla örneğe ihtiyacımız olduğunu öğrendik. Bizyapmakbirden fazla veritabanımız var, bizyapmakbirden fazla yapılandırma nesnesine sahibiz, birkaç kayıt cihazı istiyoruz . Birim testlerimiz, ortak bir örnek almak için her testte bu nesneleri yaratıp yeniden oluşturabilmek isteyebilir.

Bu yüzden bir singleton, eğer ve sadece, eğerher ikisisunduğumuz özelliklere ihtiyacımız olursa: kullanılmalıdır: Eğerneedküresel erişim (bu nadirdir, çünkü küresel kullanıcılar genellikle önerilmez) ve bizneedkimsenin önlenmesini engellemek için hiç oluşturma bir sınıfın birden fazla örneği (bu bana bir tasarım sorunu gibi geliyor). Bunun için görebilmemin tek nedeni, iki örnek oluşturmanın uygulama durumumuzu bozması - muhtemelen sınıfın bir dizi statik üye veya benzer bir saçmalık içermesidir. Bu durumda bariz cevap bu sınıfı düzeltmektir. Tek örnek olmaya bağlı olmamalı.

Bir nesneye genel erişime ihtiyacınız varsa, onu _std::cout_ gibi bir global yapın. Ancak, yaratılabilecek örneklerin sayısını sınırlamayın.

Kesinlikle, bir sınıfın örnek sayısını yalnızca bir taneyle sınırlandırmanız gerekiyorsa ve ikinci bir örnek oluşturmanın güvenli bir şekilde ele alınmasının hiçbir yolu yoktur, o zaman bunu uygulayın. Ancak bunu küresel olarak da erişilebilir kılmayın.

Her iki özelliğe de ihtiyacınız varsa, o zaman 1) bunu bir singleton yapın ve 2) bunun için neye ihtiyacınız olduğunu söyleyin, çünkü böyle bir durumu hayal etmekte zorlanıyorum.

71
jalf

Singleton'lardaki sorun onların uygulanması değil. Bu, ikisi de açıkça arzu edilmeyen iki farklı kavramı bir araya getirmeleridir.

1) Singletons, bir nesneye genel erişim mekanizması sağlar. Her ne kadar iyi tanımlanmış bir başlatma emri olmayan dillerde marjinal olarak daha güvenli ve marjinal olarak daha güvenilir olabilirlerse de, bu kullanım hala global bir değişkenin ahlaki karşılığıdır. Bu garip bir sözdiziminde (g_foo yerine foo :: get_instance ()) giyinmiş, ancak aynı amaca hizmet eder (tüm program boyunca erişilebilen tek bir nesne) ve aynı dezavantajlara sahiptir.

2) Singletons, bir sınıfın birden fazla örneğini engeller. Nadirdir, IME, bu özelliklerin bir sınıfa dönüştürülmesi gerekir. Normalde çok daha bağlamsal bir şey; Tek-ve-tek olarak kabul edilen şeylerin çoğu gerçekten sadece-sadece-bir-olur. IMO'ya daha uygun bir çözüm, yalnızca bir örnek oluşturmaktır - birden fazla örneğe ihtiyacınız olduğunu anlayana kadar.

35
DrPizza

Desenli bir şey: genelleme. Yararlı olduklarında ve başarısız olduklarında tüm davaları vardır.

Tek yapmanız gereken test kodunuz gerektiğinde kötü olabilir. Genelde sınıfın bir örneği ile sıkışıp kalıyorsunuz ve yapıcıda bir kapı açmak veya durumu sıfırlamak için bazı yöntemler arasında seçim yapabilirsiniz.

Diğer bir problem ise, Singleton'un aslında global değişken kılık değiştirmesinden başka bir şey olmamasıdır. Programınız üzerinde çok fazla küresel paylaşılan bir durum olduğunda, işler geri dönme eğilimindedir, hepimiz biliyoruz.

bağımlılık takibi zor yapabilir. Her şey Singleton'unuza bağlı olduğunda, değiştirmek, ikiye bölünmek vb. İçin daha zordur. Bu aynı zamanda esnekliği de engeller. Bu sorunu hafifletmek için bir miktar Bağımlılık Enjeksiyon çerçevesini araştırın.

26
Paweł Hajdan

Singletons, temel olarak, karmaşık global değişkenlere sahip olmanızı zorlaştıran veya imkansızlaştıran dillerdeki karmaşık global duruma sahip olmanıza izin verir.

Özellikle Java, tekilleri global değişkenlerin yerine kullanır, çünkü her şey bir sınıf içinde yer almalıdır. Global değişkenlere en yakın olanı _import static_ ile globalmiş gibi kullanılabilecek ortak statik değişkenlerdir.

C++ 'nın global değişkenleri vardır, ancak global sınıf değişkenlerinin yapıcılarının çağrıldığı sıra tanımlanmamıştır. Dolayısıyla, bir singleton, bu değişkenin ilk defa kullanılmasına kadar global bir değişkenin oluşumunu ertelemenize izin verir.

Python ve Ruby gibi diller singletonları çok az kullanır, çünkü bunun yerine global değişkenleri bir modül içinde kullanabilirsiniz.

Peki, ne zaman bir singleton kullanmak iyi/kötü? Hemen hemen tam olarak ne zaman küresel bir değişken kullanmak iyi/kötü olacağını.

12
Eli Courtwright
  • Bir Singleton'ı doğru olarak nasıl uygularsınız?

Daha önce bahsetmediğim bir konu var, önceki bir işte karşılaştığım bir şey. DLL'ler arasında paylaşılan C++ singleton'lar vardı ve bir sınıfın tek bir örneğini sağlama alışkanlığı işe yaramadı. Sorun şu ki, her DLL, EXE ile birlikte kendi statik değişken setlerini elde ediyor. Get_instance işleviniz satır içi veya statik bir kütüphanenin parçasıysa, her DLL kendi "singleton" kopyasıyla birlikte açılır.

Çözüm, singleton kodunun yalnızca bir DLL veya EXE içinde tanımlandığından emin olmak veya örnekleri ayrıştırmak için bu özelliklere sahip bir singleton yöneticisi oluşturmaktır.

6
Mark Ransom

Modern C++ Design Alexandrescu tarafından iş parçacığı güvenli, kalıtımsal bir singleton vardır.

2p değerim için, tekilleriniz için yaşamları tanımlamanın önemli olduğunu düşünüyorum (bunları kullanmak kesinlikle gerekli olduğunda). Normalde, statik get() işlevinin hiçbir şeyi başlatmasına izin vermem ve ana uygulamanın bazı bölümlerine kurulum ve imha bırakmam. Bu, tekiller arasındaki bağımlılıkları vurgulamaya yardımcı olur - ancak yukarıda vurgulandığı gibi, mümkünse bunlardan kaçınmak en iyisidir.

6
tenpn

İlk örnek iş parçacığı güvenli değil - eğer iki iş parçacığı aynı anda getInstance'ı çağırırsa, bu statik bir PITA olacak. Bir çeşit muteks yardımcı olabilir.

5
Rob

Diğerlerinin de belirttiği gibi, singleton'ların ana dezavantajları, onları uzatma yeteneğini ve birden fazla örneği örnekleme gücünün kaybolduğunu; test amaçlı.

Singletonların bazı yararlı yönleri:

  1. tembel veya açık örnekleme
  2. kurulum ve/veya durum gerektiren bir nesne için kullanışlı

Ancak, bu avantajlardan yararlanmak için bir singleton kullanmak zorunda değilsiniz. İşi yapan normal bir nesne yazabilir ve daha sonra insanların bir fabrikadan erişmesini sağlayabilirsiniz (ayrı bir nesne). Fabrika, gerektiğinde yalnızca birini başlatmak, yeniden kullanmak vb. İçin endişelenebilir. Ayrıca, somut bir sınıftan ziyade bir arayüz programlıyorsanız, fabrika stratejileri kullanabilir, yani arayüzün çeşitli uygulamalarını açıp kapatabilirsiniz.

Son olarak, bir fabrika kendisini Spring vb. Gibi bağımlılık enjeksiyon teknolojilerine borçludur.

4
lexh

Bir singleton yalnızca bir örnek oluşturulmasına izin verdiği için, örnek kopyalamayı etkin bir şekilde kontrol eder. örneğin, bir arama için birden fazla örneğe ihtiyacınız olmaz - örneğin bir mors arama haritası, bu nedenle onu singleton sınıfına sığdırmak uygun olur. Ve sadece sınıfın tek bir örneğine sahip olmanız, bu örneğe yapılan referansların sayısıyla da sınırlı olduğunuz anlamına gelmez. Çağrıları sıraya koyabilir (diş açma sorunlarından kaçınmak için) örneğe ve gerekli değişiklikleri uygulamaya koyabilirsiniz. Evet, bir singleton'ın genel formu global olarak halka açıktır, tasarımı daha kısıtlı bir singleton oluşturmak için kesinlikle değiştirebilirsiniz. Bunu daha önce yormamıştım ama bunun mümkün olduğunu biliyorum. Ve singleton deseninin tamamen kötülük olduğunu söyleyen herkese şunu bilmelisiniz: evet, doğru kullanmazsanız ya da içinde etkili işlevsellik ve öngörülebilir davranışla sınırlı kalmazsanız, kötülüktür: GENELLEŞTİRMEYİN.

3
gogole

Singletons, başlattığınızda ve itiraz ettiğinizde çalıştırılan çok sayıda kodunuz olduğunda kullanışlıdır. Örneğin, bir kalıcılık nesnesi ayarlarken iBatis kullanırken tüm yapılandırmaları okuması, haritaları ayrıştırması, kodunu almadan önce doğru olduğundan emin olmanız gerekir.

Bunu her zaman yaptıysanız, performans çok düşecektir. Bunu bir singletonda kullanarak, bu vuruşu bir kez alırsınız ve sonra gelen tüm çağrılar bunu yapmak zorunda değildir.

3
Brian

Çoğu insan, global değişkeni kullanma konusunda kendilerini iyi hissettirmeye çalışırken, singleton'ları kullanır. Meşru kullanımlar var, ancak insanların onları kullandığı zamanlar, yalnızca bir vakanın olabileceği gerçeği, küresel olarak erişilebilir olduğu gerçeğiyle karşılaştırıldığında önemsiz bir gerçek.

3
Brad Barker

Singletons'ın asıl çöküşü mirastan kopmalarıdır. Singleton'un başvuruda bulunduğu koda erişiminiz olmadığı sürece size genişletilmiş işlevsellik sağlamak için yeni bir sınıf türetemezsiniz. Bu yüzden, Singleton kodunuzu sıkı bir şekilde bir araya getirecek (Strateji Deseni ... yani Bağımlılık Enjeksiyonu ile sabitlenebilir) kodunun bölümlerini revizyondan (paylaşılan kütüphaneler) kapatmanızı önleyecektir.

Bu yüzden, logger veya iş parçacığı havuzu örnekleri bile geçersiz ve stratejiler ile değiştirilmelidir.

3
ZebZiggle

Ama bir Singleton gibi bir şeye ihtiyacım olduğunda, onu başlatmak için genellikle Schwarz Counter kullanıyorum.

2
Matt Cruikshank

Singletons'ı röportaj testi olarak kullanıyorum.

Bir geliştiriciden bazı tasarım modellerini adlandırmasını istediğimde, tek adlarının hepsi Singleton ise, işe alınmazlar.

1
Matt Cruikshank

Aşağıda, hafızayı imha makinesinin kendisinde ayırmakla iş parçacığı güvenli bir singleton deseni uygulamak için daha iyi bir yaklaşım vardır. Ancak yıkıcının isteğe bağlı olması gerektiğini düşünüyorum çünkü program sonlandığında singleton örneği otomatik olarak imha edilecek:

#include<iostream>
#include<mutex>

using namespace std;
std::mutex mtx;

class MySingleton{
private:
    static MySingleton * singletonInstance;
    MySingleton();
    ~MySingleton();
public:
    static MySingleton* GetInstance();
    MySingleton(const MySingleton&) = delete;
    const MySingleton& operator=(const MySingleton&) = delete;
    MySingleton(MySingleton&& other) noexcept = delete;
    MySingleton& operator=(MySingleton&& other) noexcept = delete;
};

MySingleton* MySingleton::singletonInstance = nullptr;
MySingleton::MySingleton(){ };
MySingleton::~MySingleton(){
    delete singletonInstance;
};

MySingleton* MySingleton::GetInstance(){
    if (singletonInstance == NULL){
        std::lock_guard<std::mutex> lock(mtx);
        if (singletonInstance == NULL)
            singletonInstance = new MySingleton();
    }
    return singletonInstance;
}

Tekli sınıfları kullanmamız gereken durumlar ile ilgili olabilir - Programın yürütülmesi sırasında örneğin durumunu korumak istiyorsak, Dosyanın sadece bir örneğinin ihtiyaç duyduğu bir uygulamanın yürütme günlüğüne yazıyorsak, Kullanılacak .... ve benzeri. Yukarıdaki kodumda bir optimizasyon önerilebilirse, bu anlamlı olacaktır.

1
A. Gupta

Meyers singleton modeli çoğu zaman yeterince iyi çalışır ve bazı durumlarda daha iyi bir şey aramak için mutlaka ödeme yapmaz. Kurucu asla atmayacağı ve tekiltonlar arasında bir bağımlılık olmadığı sürece.

Bir singleton, tüm GAO'lar singleton olmasa da global olarak erişilebilir bir nesne (bundan böyle GAO) için bir uygulamadır.

Kayıtçıların kendileri tekil olmamalı, ancak kayıt tutma aracı, kayıt mesajının nereden veya nasıl kaydedildiğini nereden oluşturduğunu ayırmak için ideal olarak global olarak erişilebilir olmalıdır.

Tembel yükleme/tembel değerlendirme farklı bir konsepttir ve singleton da genellikle bunu uygular. Özellikle iş güvenliği ve kendi sorunları ile birlikte gelir; o zamanlar iyi bir fikir gibi görünen şeylerin sonuçta çok iyi olmadığı ortaya çıkmaz. (Dizelerde COW uygulaması gibi biraz).

Bunu akılda tutarak, GOA'lar şöyle başlatılabilir:

namespace {

T1 * pt1 = NULL;
T2 * pt2 = NULL;
T3 * pt3 = NULL;
T4 * pt4 = NULL;

}

int main( int argc, char* argv[])
{
   T1 t1(args1);
   T2 t2(args2);
   T3 t3(args3);
   T4 t4(args4);

   pt1 = &t1;
   pt2 = &t2;
   pt3 = &t3;
   pt4 = &t4;

   dostuff();

}

T1& getT1()
{
   return *pt1;
}

T2& getT2()
{
   return *pt2;
}

T3& getT3()
{
  return *pt3;
}

T4& getT4()
{
  return *pt4;
}

Bunun kadar kabaca yapılmasına gerek yoktur ve açık bir şekilde, muhtemelen başka bir mekanizmanın yaşamlarını yönetmesini istediğiniz nesneleri içeren yüklü bir kütüphanede. (Kitaplığı yüklediğinizde aldığınız bir nesneye koyun).

Singletons kullandığımda gelince? Bunları 2 şey için kullandım - Hangi kitaplıkların dlopen'e yüklendiğini belirten bir singleton tablosu - Kaydedicilerin abone olabileceği ve mesaj gönderebileceğiniz bir ileti işleyicisi. Sinyal işleyicileri için özel olarak gereklidir.

0
CashCow

Eğer singleton'ı yaratan ve kullanan kişi sizseniz, bunu singleton olarak yapmayın (mantıklı değil çünkü nesnenin tekilliğini singleton yapmadan kontrol edebilirsiniz.) Kütüphane ve kullanıcılarınıza yalnızca bir nesne sağlamak istiyorsunuz (bu durumda, singleton'ı oluşturan sizsiniz, ancak kullanıcı değilsiniz).

Singletonlar nesnelerdir, bu yüzden onları nesneler olarak kullanırlar, birçok kişi doğrudan onu döndüren yöntemi çağırmak suretiyle singletonlara erişir, ancak bu zararlıdır çünkü kodunuzu nesnenin singleton olduğunu bildiğiniz için yaparsınız, singletonları nesne olarak kullanmayı tercih ederim yapıcı aracılığıyla ve onları sıradan nesneler olarak kullanıyorum, bu şekilde, kodunuz bu nesnelerin tekil olup olmadığını ve bağımlılıkların daha net yapıldığını bilmiyor ve refactoring için biraz yardımcı oluyor ...

0
La VloZ Merrill

Anti-Kullanımı:

Aşırı tekil kullanımla ilgili büyük sorunlardan biri, kalıbın alternatif uygulamaların kolay uzatılmasını ve değiştirilmesini engellemesidir. Sınıf ismi, singleton'un kullanıldığı her yerde kodlanmıştır.

0
Adam Franco

Çok fazla bellek barındıran bir sınıfım olduğunda onları faydalı buluyorum. Mesela üzerinde çalıştığım son bir oyunda, çok büyük bitişik hafıza dizileri içeren bir etki haritası sınıfım var. Hepsinin başlangıçta tahsis edilmesini, kapanışta serbest kalmasını ve kesinlikle sadece bir kopyasını istiyorum. Ayrıca birçok yerden erişmem gerekiyor. Bu durumda singleton desenini çok faydalı buluyorum.

Başka çözümler olduğuna eminim ama bunu çok kullanışlı ve uygulaması kolay buluyorum.

0

Bence bu C # için en sağlam versiyondur :

using System;
using System.Collections;
using System.Threading;

namespace DoFactory.GangOfFour.Singleton.RealWorld
{

  // MainApp test application

  class MainApp
  {
    static void Main()
    {
      LoadBalancer b1 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b2 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b3 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b4 = LoadBalancer.GetLoadBalancer();

      // Same instance?
      if (b1 == b2 && b2 == b3 && b3 == b4)
      {
        Console.WriteLine("Same instance\n");
      }

      // All are the same instance -- use b1 arbitrarily
      // Load balance 15 server requests
      for (int i = 0; i < 15; i++)
      {
        Console.WriteLine(b1.Server);
      }

      // Wait for user
      Console.Read();    
    }
  }

  // "Singleton"

  class LoadBalancer
  {
    private static LoadBalancer instance;
    private ArrayList servers = new ArrayList();

    private Random random = new Random();

    // Lock synchronization object
    private static object syncLock = new object();

    // Constructor (protected)
    protected LoadBalancer()
    {
      // List of available servers
      servers.Add("ServerI");
      servers.Add("ServerII");
      servers.Add("ServerIII");
      servers.Add("ServerIV");
      servers.Add("ServerV");
    }

    public static LoadBalancer GetLoadBalancer()
    {
      // Support multithreaded applications through
      // 'Double checked locking' pattern which (once
      // the instance exists) avoids locking each
      // time the method is invoked
      if (instance == null)
      {
        lock (syncLock)
        {
          if (instance == null)
          {
            instance = new LoadBalancer();
          }
        }
      }

      return instance;
    }

    // Simple, but effective random load balancer

    public string Server
    {
      get
      {
        int r = random.Next(servers.Count);
        return servers[r].ToString();
      }
    }
  }
}

İşte . NET’in optimize edilmiş hali :

using System;
using System.Collections;

namespace DoFactory.GangOfFour.Singleton.NETOptimized
{

  // MainApp test application

  class MainApp
  {

    static void Main()
    {
      LoadBalancer b1 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b2 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b3 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b4 = LoadBalancer.GetLoadBalancer();

      // Confirm these are the same instance
      if (b1 == b2 && b2 == b3 && b3 == b4)
      {
        Console.WriteLine("Same instance\n");
      }

      // All are the same instance -- use b1 arbitrarily
      // Load balance 15 requests for a server
      for (int i = 0; i < 15; i++)
      {
        Console.WriteLine(b1.Server);
      }

      // Wait for user
      Console.Read();    
    }
  }

  // Singleton

  sealed class LoadBalancer
  {
    // Static members are lazily initialized.
    // .NET guarantees thread safety for static initialization
    private static readonly LoadBalancer instance =
      new LoadBalancer();

    private ArrayList servers = new ArrayList();
    private Random random = new Random();

    // Note: constructor is private.
    private LoadBalancer()
    {
      // List of available servers
      servers.Add("ServerI");
      servers.Add("ServerII");
      servers.Add("ServerIII");
      servers.Add("ServerIV");
      servers.Add("ServerV");
    }

    public static LoadBalancer GetLoadBalancer()
    {
      return instance;
    }

    // Simple, but effective load balancer
    public string Server
    {
      get
      {
        int r = random.Next(servers.Count);
        return servers[r].ToString();
      }
    }
  }
}

Bu deseni dotfactory.com adresinde bulabilirsiniz.

0
artur02

Bir singleton'ın neden küresel olması gerektiğini hala anlamıyorum.

Sınıf içinde bir veritabanını özel bir sabit statik değişken olarak sakladığım ve veritabanını hiç kullanmadan veritabanını kullanan sınıf fonksiyonlarını yaptığım bir singleton üretecektim.

Bu işlevselliğin neden kötü olacağını anlamıyorum.

0
Zachary Kraus