Yüceli küresel değişken - yüceli bir küresel sınıf haline gelir. Bazıları nesne odaklı tasarımı kırmayı söylüyor.
Singletonu kullanmanın mantıklı olduğu eski iyi kaydedici dışında senaryolar ver.
Yüceli küresel değişken - yüceli bir küresel sınıf haline gelir. Bazıları nesne odaklı tasarımı kırmayı söylüyor.
Singletonu kullanmanın mantıklı olduğu eski iyi kaydedici dışında senaryolar ver.
Yanıtlar:
Gerçek arayışı üzerine bir Singleton kullanmanın aslında çok az "kabul edilebilir" nedeni olduğunu keşfettim.
İnternette tekrar tekrar ortaya çıkma eğiliminin bir nedeni, (bahsettiğiniz) bir "logging" sınıfıdır. Bu durumda, bir sınıfın tek bir örneği yerine bir Singleton kullanılabilir çünkü bir günlük kaydı sınıfının genellikle bir projedeki her sınıf tarafından tekrar tekrar kullanılması gerekir. Her sınıf bu kayıt sınıfını kullanırsa, bağımlılık enjeksiyonu hantal hale gelir.
Günlüğe kaydetme, kodunuzun yürütülmesini etkilemediğinden "kabul edilebilir" bir Singleton'a özgü bir örnektir. Günlüğe kaydetmeyi devre dışı bırakın, kod yürütme aynı kalır. Aynı şekilde etkinleştirin. Misko bunu aşağıdaki şekilde Tek Köklerin Kök Nedeni'ne koyar , "Buradaki bilgiler tek yönlü akar: Uygulamanızdan kaydediciye. Günlükçüler küresel durum olsa da, günlükçülerden uygulamanıza hiçbir bilgi akışı olmadığından günlükler kabul edilebilir."
Eminim başka geçerli nedenler de vardır. Alex Miller, " Desenlerden Nefret Ediyorum " da, servis bulma ve müşteri tarafı kullanıcı arayüzlerinin muhtemelen "kabul edilebilir" seçimlerden bahsediyor.
Daha fazla oku Singleton Seni seviyorum, ama sen beni aşağı indiriyorsun.
Bir Singleton adayının üç gereksinimi karşılaması gerekir:
Önerilen Singleton'unuzda bu gereksinimlerden yalnızca bir veya ikisi varsa, yeniden tasarım neredeyse her zaman doğru seçenektir.
Örneğin, bir yazıcı biriktiricisinin birden fazla yerden çağrılması olası değildir (Yazdır menüsü), böylece eşzamanlı erişim sorununu çözmek için muteksleri kullanabilirsiniz.
Basit bir kaydedici, geçerli bir Singletonun en açık örneğidir, ancak bu daha karmaşık günlükleme düzenleriyle değişebilir.
Yalnızca başlangıçta okunması gereken yapılandırma dosyalarının okunması ve bir Singleton içinde kapsüllenmesi.
Properties.Settings.Default
NET'te benzer .
Paylaşılan bir kaynağı yönetmeniz gerektiğinde tek birton kullanırsınız. Örneğin bir yazıcı biriktiricisi. Aynı kaynak için çakışan isteklerden kaçınmak için uygulamanızda biriktiricinin yalnızca tek bir örneği olmalıdır.
Veya bir veritabanı bağlantısı veya bir dosya yöneticisi vb.
Bazı genel durumları (kullanıcı dili, yardım dosyayolu, uygulama yolu) saklayan tekiltonlar makul. İş mantığını kontrol etmek için tekil düğmeler kullanmaya özen gösterin - tekil neredeyse her zaman birden fazla olur
Veritabanına bağlantıyı (veya bağlantı havuzunu) yönetme.
Harici yapılandırma dosyalarındaki bilgileri almak ve saklamak için de kullanırım.
Tek birtonu kullanmanın yollarından biri, bir kaynağa erişimi denetleyen tek bir "aracı" olması gereken bir örneği kapsamaktır. Singletons günlükçülerde iyidir çünkü bir dosyaya yalnızca aracılık olarak erişilebilen bir aracıya erişim sağlarlar. Günlüğe kaydetme gibi bir şey için, yazmaları bir günlük dosyası gibi bir şeye soyutlamanın bir yolunu sağlarlar - tekli önbelleğinize vb.
Ayrıca, birçok pencere / iş parçacığı / vb. İçeren bir uygulamanız olduğu, ancak tek bir iletişim noktası gerektiren bir durum düşünün. Bir keresinde, uygulamamın başlatılmasını istediğim işleri kontrol etmek için birini kullandım. Singleton, işleri serileştirmekten ve durumlarını programın ilgilenilen diğer herhangi bir bölümüne göstermekten sorumluydu. Bu tür bir senaryoda, bir singletona uygulamanızın içinde çalışan bir "sunucu" sınıfı gibi bakabilirsiniz ... HTH
Tüm uygulama tarafından paylaşılan bir kaynağa erişimi yönetirken tek birton kullanılmalıdır ve potansiyel olarak aynı sınıfın birden çok örneğine sahip olmak yıkıcı olacaktır. Paylaşılan kaynaklara güvenli erişimin bu tür bir modelin hayati önem taşıyabileceğinin çok iyi bir örneği olduğundan emin olmak.
Singletons kullanırken, bağımlılıkları yanlışlıkla gizlemediğinizden emin olmalısınız. İdeal olarak, tektonlar (bir uygulamadaki çoğu statik değişken gibi), uygulama için başlatma kodunuzun yürütülmesi sırasında ayarlanmalıdır (C # yürütülebilir dosyalar için statik void Main (), java yürütülebilirler için statik void main ()) ve ardından gerektiren tüm diğer sınıflar. Bu, test edilebilirliği korumanıza yardımcı olur.
Pratik bir örnek, Test :: Builder'da bulunabilir hemen hemen her modern Perl test modülünü destekleyen Sınıf . Test :: Builder singleton, test sürecinin durumunu ve geçmişini (geçmiş test sonuçları, çalıştırılan test sayısını sayar) ve test çıktısının nereye gittiği gibi şeyleri depolar ve aracılar. Bunların hepsi, farklı yazarlar tarafından yazılan çoklu test modüllerini tek bir test komut dosyasında birlikte çalışmak için koordine etmek için gereklidir.
Test :: Builder'ın singletonunun tarihi eğiticidir. Aramak new()
her zaman aynı nesneyi verir. İlk olarak, tüm veriler nesnenin kendisinde hiçbir şey olmadan sınıf değişkenleri olarak saklandı. Bu Test :: Builder'ın kendisini test etmek isteyene kadar çalıştı. Daha sonra davranışını ve çıktısını yakalamak ve test etmek ve biri gerçek test nesnesi olmak için bir kukla olarak bir kurulum olmak üzere iki Test :: Builder nesnesine ihtiyacım vardı. Bu noktada Test :: Builder gerçek bir nesneye dönüştürüldü. Singleton nesnesi sınıf verisi olarak saklanır ve new()
her zaman onu döndürür. create()
yeni bir nesne oluşturmak ve testi etkinleştirmek için eklendi.
Şu anda, kullanıcılar Test :: Builder'ın bazı davranışlarını kendi modüllerinde değiştirmek istiyorlar, ancak test geçmişi tüm test modüllerinde ortak kalırken, diğerlerini yalnız bırakıyorlar. Şimdi olan şey, monolitik Test :: Builder nesnesinin onları bir araya getiren Test :: Builder örneği ile daha küçük parçalara (geçmiş, çıktı, biçim ...) bölünmesidir. Şimdi Test :: Builder artık bir singleton olmak zorunda değil. Tarih gibi bileşenleri de olabilir. Bu, bir tektonun esnek olmayan gereksinimini bir seviyeye iter. Parçaları karıştırmak ve eşleştirmek için kullanıcıya daha fazla esneklik sağlar. Daha küçük tekil nesneler artık verileri depolayabilir ve içerdikleri nesneler nasıl kullanılacağına karar verir. Hatta bir Test :: Builder sınıfının Test :: Builder geçmişini ve çıktı tektonlarını kullanarak oynatmasına izin verir.
Veri bütünlüğünü sağlamak için mümkün olan en küçük miktarda davranışa sahip olan tek paylaşılan verilerin etrafına singleton konularak hafifletilebilen verilerin koordinasyonu ile davranış esnekliği arasında bir itme ve çekme var gibi görünüyor.
Veritabanından veya dosyadan bir yapılandırma Özellikleri nesnesi yüklediğinizde, bu nesnenin tekli bir öğeye sahip olmasına yardımcı olur; sunucu çalışırken değişmeyecek statik verileri yeniden okumaya devam etmek için bir neden yoktur.
Durum modelini uygularken (GoF kitabında gösterildiği gibi) Singleton'u kullanabilirsiniz. Bunun nedeni, somut Devlet sınıflarının kendilerine ait bir durumlarının olmaması ve eylemlerini bir bağlam sınıfı açısından gerçekleştirmeleridir.
Ayrıca Soyut Fabrika'yı bir singleton yapabilirsiniz.
setState()
Devlet yaratma politikasına karar vermekten sorumlu olmaya çalışın . Programlama dilinizin şablonları veya jenerikleri desteklemesi yardımcı olur. Singleton yerine, bir durum nesnesinin somutlaştırılmasının aynı global / statik durum nesnesini yeniden kullanacağı Monostate desenini kullanabilirsiniz . Durumu değiştirmek için sözdizimi değişmeden kalabilir, çünkü kullanıcılarınızın somutlaştırılmış durumun bir Monostate olduğunun farkında olması gerekmez.
Paylaşılan kaynaklar. Özellikle PHP'de bir veritabanı sınıfı, bir şablon sınıfı ve bir global değişken depo sınıfı. Tümünün kod boyunca kullanılan tüm modüller / sınıflar tarafından paylaşılması gerekir.
Bu gerçek bir nesne kullanımıdır -> şablon sınıfı, oluşturulmakta olan sayfa şablonunu içerir ve sayfa çıktısına eklenen modüller tarafından şekillendirilir, eklenir, değiştirilir. Bunun olabilmesi için tek bir örnek olarak saklanması gerekir ve aynı şey veritabanları için de geçerlidir. Paylaşılan bir veritabanı singletonu ile, tüm modüllerin sınıfları sorgulara erişebilir ve bunları yeniden çalıştırmak zorunda kalmadan alabilir.
Global değişken depo tekli, size küresel, güvenilir ve kolay kullanılabilir bir değişken depo sağlar. Kodunuzu çok fazla düzenler. Bir dizideki tüm yapılandırma değerlerinin tek birtondaki gibi olduğunu düşünün:
$gb->config['hostname']
veya aşağıdaki gibi bir dizideki tüm dil değerlerine sahip olmak:
$gb->lang['ENTER_USER']
Sayfanın kodunu çalıştırmanın sonunda, şimdi olgunlaşın:
$template
Singleton, $gb
yerine geçmesi için lang dizisine sahip bir singleton ve tüm çıktı yüklenmiş ve hazır. Bunları, şimdi olgun şablon nesnesinin sayfa değerinde bulunan anahtarların yerine koyar ve daha sonra kullanıcıya sunarsınız.
Bunun en büyük avantajı, istediğiniz herhangi bir işlem sonrası herhangi bir işlem yapabilmenizdir. Tüm dil değerlerini google translate veya başka bir translate hizmetine aktarabilir ve bunları geri alabilir ve örneğin, çevrilmiş yerlerine değiştirebilirsiniz. veya sayfa yapılarında veya içerik dizelerinde istediğiniz gibi değiştirebilirsiniz.
Belirli altyapı kaygılarını tekil veya küresel değişkenler olarak yapılandırmak çok pragmatik olabilir. Buna en sevdiğim örnek, çerçeveye bağlantı noktası olarak tektonları kullanan Bağımlılık Enjeksiyonu çerçeveleridir.
Bu durumda, kitaplığı kullanmayı basitleştirmek ve gereksiz karmaşıklığı önlemek için altyapıya bağımlı olursunuz.
Takılabilir modüllerle uğraşırken komut satırı parametrelerini kapsayan bir nesne için kullanıyorum. Ana program, yüklenen modüller için komut satırı parametrelerinin ne olduğunu bilmez (ve hangi modüllerin yüklendiğini her zaman bilmez). Örneğin, herhangi bir parametreye ihtiyaç duymayan ana yükler A (neden fazladan bir işaretçi / referans / ne olursa olsun, emin değilim - kirlilik gibi görünüyor), sonra X, Y ve Z modüllerini yükler. bunlardan, örneğin X ve Z, parametrelere ihtiyaç duyar (veya kabul eder), bu nedenle hangi parametrelerin kabul edileceğini söylemek için komut satırı singletonunu geri çağırırlar ve çalışma zamanında kullanıcının gerçekten herhangi bir onları.
Birçok yönden, sorgu başına yalnızca bir işlem kullanıyorsanız (diğer mod_ * yöntemleri bunu yapmazsa, CGI parametrelerini işlemek için bir singleton benzer şekilde çalışacaktır, bu yüzden orada kötü olurdu - bu yüzden yapmamanız gerektiğini söyleyen argüman t mod_perl'e veya herhangi bir dünyaya bağlantı kurmanız durumunda mod_cgi dünyasında singletons kullanın).
Belki de kodlu bir örnek.
Burada ConcreteRegistry, bir poker oyununda, paket ağacının oyunun birkaç temel çekirdeğine (yani model, görünüm, kontrolör, çevre vb.
http://www.edmundkirwan.com/servlet/fractal/cs1/frac-cs40.html
Ed.
1 - İlk cevap hakkında bir yorum:
Statik Logger sınıfına katılmıyorum. bu bir uygulama için pratik olabilir, ancak birim testi için değiştirilemez. Statik bir sınıf, bir test çiftiyle değiştirilemez. Birim testi yapmazsanız, sorunu burada görmezsiniz.
2 - Elle bir singleton oluşturmamaya çalışıyorum. Yalnızca, ortakları nesneye enjekte etmeme izin veren yapıcılar ile basit bir nesne oluşturuyorum. Bir singletona ihtiyacım olsaydı, bir bağımlılık inyection çerçevesi (Spring.NET, Unity for .NET, Spring for Java) ya da başka bir şey kullanırdım.
ILogger logger = Logger.SingleInstance();
bu yöntemin statik olduğu ve bir ILogger öğesinin statik olarak depolanmış bir örneğini döndürdüğü durumlarda. "Bir bağımlılık enjeksiyon çerçevesi" örneğini kullandınız. Neredeyse tüm DI kapları tek tonludur; konfigürasyonları statik olarak tanımlanır ve sonuçta tek bir servis sağlayıcı arayüzünden erişilir / depolanır.