Oyun mimarimde birçok singleton bulundurmaktan nasıl kaçınabilirim?


55

Oyun oluşturmak için cocos2d-x oyun motorunu kullanıyorum. Motor zaten birçok tekil kullanır. Birisi kullandıysa, o zaman bazılarına aşina olmalı:

Director
SimpleAudioEngine
SpriteFrameCache
TextureCache
EventDispatcher (was)
ArmatureDataManager
FileUtils
UserDefault

ve daha pek çoğu, yaklaşık 16 derslik. Bu sayfada benzer bir liste bulabilirsiniz: Cocos2d-html5 v3.0 içindeki Singleton nesneleri Ancak yazmak istediğimde oyun oynamak için çok daha fazla singleton'a ihtiyacım var:

PlayerData (score, lives, ...)
PlayerProgress (passed levels, stars)
LevelData (parameters per levels and level packs)
SocialConnection (Facebook and Twitter login, share, friend list, ...)
GameData (you may obtain some data from server to configure the game)
IAP (for in purchases)
Ads (for showing ads)
Analytics (for collecting some analytics)
EntityComponentSystemManager (mananges entity creation and manipulation)
Box2dManager (manages the physics world)
.....

Neden onların singleton olması gerektiğini düşünüyorum? Çünkü onlara oyunumda çok farklı yerlerde ihtiyacım olacak ve paylaşılan erişim çok kullanışlı olurdu. Başka bir deyişle, onları bir yerde yaratacak ve işaretçilerimi tüm mimarime iletecek çok zor olacağı için anlamıyorum. Ayrıca bunlar sadece bir tane ihtiyacım olan şeyler. Her durumda birkaç kişiye ihtiyacım olacak, ben de bir Multiton deseni kullanabilirim. Ancak en kötüsü, Singleton’ın şu sebeplerden dolayı en ağır biçimde eleştirilen model olmasıdır:

 - bad testability
 - no inheritance available
 - no lifetime control
 - no explicit dependency chain
 - global access (the same as global variables, actually)
 - ....

Burada bazı düşünceleri bulabilirsiniz: https://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons ve https://stackoverflow.com/questions/4074154/when-should-the-singleton -pattern--kullanılmamalıdır-yanında-bariz

Sanırım yanlış bir şey yapıyorum. Sanırım kodum kokuyor . :) Daha deneyimli oyun geliştiricilerinin bu mimari problemi nasıl çözdüğünü tahmin ediyorum? Kontrol etmek istiyorum, belki de oyun geliştirmede , halihazırda oyun motorunda olanları düşünen 30'dan fazla singleton olması normaldir .

İhtiyacım olan tüm bu sınıfların örneklerine sahip olacak bir Singleton-Cephe kullanmayı düşündüm, ancak her biri zaten bir tekillik olmayacaktı. Bu, birçok sorunu ortadan kaldıracak ve Cephe'nin kendisi olacak tek bir singleton olacaktı. Ancak bu durumda başka bir tasarım problemim olacak. Cephe bir ALLAH NESNE olacak. Sanırım bu da kokuyor . Bu yüzden bu durum için iyi bir tasarım çözümü bulamıyorum. Lütfen tavsiye.


26
Singleton'a karşı çıkan çoğu kişi, bazı verileri / işlevleri tüm kodlar üzerinden yaymak için gereken çalışmanın, bir Singleton kullanmaktan daha fazla hata kaynağı olabileceğini fark etmiyor gibi görünüyor. Yani temelde karşılaştırma yapmıyorlar, sadece reddediyorlar ==> Anti-Singletonism'in bir Duruş Olmasından şüpheleniyorum :-) Çok iyi, Singleton'un kusurları var, bu yüzden eğer ondan kaçınabilirseniz, onunla birlikte gelen sorunları önlemek için , şimdi yapamıyorsanız, geriye bakmadan gidin. Sonuçta, Cocos2d, 16 Singleton'unda gayet iyi çalışıyor gibi görünüyor ...
GameAlchemist

6
Hatırlatma olarak, bu belirli bir görevin nasıl yerine getirileceğiyle ilgili bir sorudur. Bu, singleton'ların pro-con tartışmalarını soran bir soru değildir (burada yine de konu dışı olacaktır). Ayrıca, yorumların, singletonların artıları ve eksileri hakkında teğetsel bir tartışma için bir platform olarak değil, askerden açıklama talep etmek için kullanılması gerektiğini unutmayın. Girdiyi sağlamak istiyorsanız, bunu yapmanın doğru yolu , çözümünüzü singleton deseninde veya aleyhinde tavsiyelerde bulunarak meşru bir şekilde cevaplamaktır .
Josh

Bu singletonların küresel olarak erişilebilir olduğunu varsayıyorum? Bu kalıptan kaçınmak için bir sebep olurdu.
Peter - Monica'yı yeniden

Yanıtlar:


41

Servislerimi ana uygulama sınıfımda başlatıyorum ve daha sonra bunları inşaatçılar veya fonksiyonlar aracılığıyla kullanmak için ihtiyaç duydukları şeylere işaretçiler olarak aktarıyorum. Bu iki nedenden dolayı faydalıdır.

Birincisi, başlatma ve temizleme sırası basit ve açıktır. Kazanan bir hizmeti tek birtonla yapabildiğiniz gibi başka bir yerden başlatmanız mümkün değildir.

İkincisi, kimin neye bağlı olduğu belli. Sadece sınıf bildiriminde hangi sınıfların hangi hizmetlere ihtiyaç duyduğunu kolayca görebilirim.

Tüm bu nesnelerin etrafından dolaştırılmasının can sıkıcı olduğunu düşünebilirsiniz, ancak sistem iyi tasarlanmışsa, hiç de fena değil ve her şeyi daha net hale getirir (benim için).


34
+1. Ayrıca, sistemlere referansları iletmek zorunda kalmanın "sıkıntısı", bağımlılık sünmesini önlemeye yardımcı olur; eğer bir şeyi " her şeye " aktarmak zorundaysanız , bu, tasarımınızda kötü bir bağlantı problemi olduğunun iyi bir işaretidir ve bu yolla, her yerden her şeye küresel çapta erişime sahip olmaktan çok daha belirgindir.
Josh

2
Bu aslında bir çözüm sağlamaz ... bu yüzden program sınıfınızda içinde bir sürü singleton nesnesi var ve şimdi sahnede yer alan bir kodun 10 seviyesi bu singletonlardan birine ihtiyaç duyuyor ... nasıl geçti?
Savaş

Wardy: Neden singleton olmaları gerekiyor? Elbette, çoğunlukla belirli bir örneği geçiyor olabilirsiniz, ancak bir singleton'u singleton yapan şey, farklı bir örnek kullanamazsınız. Enjeksiyonla bir nesney için bir örneği, diğer nesneyi geçebilirsiniz. Sırf ne sebeple olursa olsun yapmazsın, yapamayacağın anlamına gelmez.
parar

3
Singleton değiller. Bunlar, init / cleanup'ı kontrol eden iyi tanımlanmış bir sahibi olan her şey gibi normal nesnelerdir. Erişimi olmayan 10 seviye derinlikte iseniz, belki bir tasarım sorununuz var. Her şey, yapımcılara, seslere vb. İhtiyaç duymaz veya erişemez. Bu yol size tasarımınızı düşündürür. Kodlarını test edenler için ek bir avantaj olarak (ne?), Birim testi de çok daha kolay hale gelir.
megadan

2
Evet, bağımlılık enjeksiyonunun (Spring gibi bir çerçeveyle veya çerçevesiz) bunun üstesinden gelmek için mükemmel bir çözüm olduğunu düşünüyorum. Bunu, her yere her şeyi iletmekten
megadan

17

İnternetin benden daha iyisini yapabilmesi için, singletonların arkasındaki kötülük hakkında konuşmayacağım.

Oyunlarımda tonlarca Tekli / Yönetici sahibi olmamasını önlemek için Servis Belirleme modelini kullanıyorum.

Kavram oldukça basit. Singleton olarak kullandığın şeye ulaşan tek arayüz gibi davranan sadece bir Singleton var. Birden fazla Singleton'a sahip olmak yerine, şimdi sadece bir tane var.

Gibi aramalar:

FlyingToasterManager.GetInstance().Toast();
SmokeAlarmManager.GetInstance().Start();

Servis Belirleme desenini kullanarak şuna benziyor:

SvcLocator.FlyingToaster.Toast();
SvcLocator.SmokeAlarm.Start();

Gördüğünüz gibi her Singleton Servis Bulucuda bulunur.

Daha ayrıntılı bir açıklama için, Konum Belirleme Şablonunun nasıl kullanılacağı hakkında bu sayfayı okumanızı öneririm .

[ EDIT ]: yorumlarda belirtildiği gibi gameprogrammingpatterns.com sitesi , Singleton'da çok ilginç bir bölüm içermektedir .

Umut ediyorum bu yardım eder.


4
Buraya bağlı site, gameprogrammingpatterns.com, ayrıca Singletons hakkında alakalı görünen bir bölüm de içermektedir .
ajp15243

28
Hizmet bulucular, tüm normal sorunları derleme zamanı yerine çalışma zamanına taşıyan yalnızca tekillerdir. Ancak, önerdiğiniz şey, devasa bir statik kayıt defteridir, ki bu neredeyse daha iyidir, fakat temelde hala bir küresel değişken kütlesidir. Birçok nesnenin aynı nesnelere erişmesi gerekiyorsa, bu sadece kötü bir mimari meselesidir. Doğru bağımlılık enjeksiyonu burada ihtiyaç duyulan şeydir, mevcut kürelerden farklı bir şekilde adlandırılmış küreler değil.
Magus

2
"Uygun bağımlılık enjeksiyonu" hakkında ayrıntılı bilgi verebilir misiniz?
Mavi Sihirbaz,

17
Bu gerçekten konuya yardımcı olmuyor. Esasen dev bir singletonla birleştirilmiş birçok singleton var. Altta yatan yapısal sorunların hiçbiri sabit veya hatta ele alınmadı, kod hala daha da güzel gözüküyor.
ClassicThunder

4
@classicthunder Bu her bir konuyu ele almazken, bu Singletons'a göre büyük bir gelişmedir, çünkü birkaç tanesine hitap eder. Özellikle, yazdığınız kod artık tek bir sınıfa değil, bir arabirim / sınıf kategorisine bağlanmıştır. Artık çeşitli servislerin farklı uygulamalarını kolayca değiştirebilirsiniz.
Eylül’de

12

Tüm bu cevapları, yorumları ve makaleleri okumak, özellikle de bu iki harika makaleyi,

Sonunda, kendi soruma bir nevi cevap olan şu sonuca vardım. En iyi yaklaşım tembel olmamak ve doğrudan bağımlılıkları geçmek değildir. Bu açık, test edilebilir, küresel erişim yok, delegeleri çok derin ve birçok yerde ve başka yerlerde geçirmeniz gerekiyorsa yanlış tasarım gösterebilir. Ancak programlamada bir boyut hepsine uymuyor. Bu nedenle, onları doğrudan iletmenin kullanışlı olmadığı hala devam etmektedir. Örneğin, bir oyun çerçevesi oluşturduğumuzda (farklı tür oyunlar geliştirmek için temel kod olarak yeniden kullanılacak bir kod şablonu) ve orada birçok hizmet içerir. Burada her bir hizmetin ne kadar derinden geçilebileceğini ve kaç yere ihtiyaç duyulacağını bilmiyoruz. Belirli bir oyuna bağlıdır. Peki bu tür durumlarda ne yaparız? Singleton yerine Service Locator tasarım modelini kullanıyoruz,

  1. Uygulamaları değil, arayüzleri de programlıyorsunuz. Bu, OOP müdürleri açısından çok önemlidir. Çalışma zamanında Null Object pattern kullanarak servisi değiştirebilir veya hatta devre dışı bırakabilirsiniz. Bu sadece esneklik açısından önemli değil, aynı zamanda testlerde doğrudan yardımcı olur. Ayrıca, alay, devre dışı bırakabilirsiniz, ayrıca bazı günlük ve diğer işlevler eklemek için Dekoratör desenini kullanabilirsiniz. Bu Singleton sahip olmayan çok önemli bir özelliktir.
  2. Bir diğer büyük avantaj, nesnenin ömrünü kontrol edebilmenizdir. Singleton'da nesnenin yalnızca Tembel Başlatma modeli ile ortaya çıkacağı zamanı kontrol edersiniz. Ancak nesne bir kez doğduğunda, programın sonuna kadar yaşayacak. Ancak bazı durumlarda servisi değiştirmek isteyebilirsiniz. Ya da kapat. Özellikle oyunlarda bu esneklik çok önemlidir.
  3. Birkaç Singleton'ı tek bir kompakt API'de birleştirir / sarar. Ayrıca, tek bir işlem için bir seferde birden fazla servisi kullanabilecek Cephe gibi Servis Belirleyicileri de kullanabilirsiniz.
  4. Singleton'un ana tasarım sorunu olan küresel erişime hala sahip olduğumuzu iddia edebilirsiniz. Aynı fikirdeyim, ancak bu forma yalnızca ihtiyacımız olacak, ancak küresel erişim istiyorsak. Doğrudan bağımlılık enjeksiyonunun durumumuz için kullanışlı olmadığını ve küresel bir erişime ihtiyacımız olduğunu düşünüyorsanız, küresel erişimden şikayet etmemeliyiz. Ancak bu problem için bile bir gelişme var (yukarıdaki ikinci maddeye bakınız). Tüm hizmetleri özel yapabilir ve hizmetleri kullanmaları gerektiğini düşündüğünüz tüm sınıfları Service Locator sınıfından miras alabilirsiniz. Bu, erişimi önemli ölçüde daraltabilir. Lütfen Singleton durumunda, mirası özel kurucu nedeniyle kullanamayacağınızı düşünün.

Ayrıca, bu kalıbın Unity, LibGDX, XNA'da kullanıldığını da düşünmeliyiz. Bu bir avantaj değil, ancak bu, modelin kullanılabilirliğinin bir kanıtı. Bu motorların uzun süredir akıllı geliştiriciler tarafından geliştirildiğini ve motorun evrimi sırasında hala daha iyi bir çözüm bulamadıklarını düşünün.

Sonuç olarak, Hizmet Bulucu'nun sorumumda açıklanan senaryolar için çok faydalı olabileceğini düşünüyorum, ancak mümkünse yine de kaçınılması gerekir. Temel kural olarak - mecbur kalırsanız kullanın.

EDIT: Bir yıl çalıştıktan ve doğrudan DI kullandıktan sonra, büyük inşaatçılar ve birçok delegasyonla ilgili problemler yaşadıktan sonra, daha fazla araştırma yaptım ve DI ve Hizmet Bulucu yöntemleriyle ilgili lehte ve aleyhte olanlar hakkında konuşan iyi bir makale buldum. Servis sağlayıcıların gerçekte ne zaman kötü olduklarını açıklayan Martin Fowler tarafından yayınlanan bu makaleye ( http://www.martinfowler.com/articles/injection.html ) bakınız:

Bu nedenle, asıl mesele yazarın kontrolü dışındaki uygulamalarda kullanılması beklenen kod yazan insanlar içindir. Bu durumlarda bir Servis Bulucu ile ilgili asgari bir varsayım bile bir problemdir.

Ama yine de, eğer ilk kez bize DI yapmak istiyorsanız, bu http://misko.hevery.com/2008/10/21/dependency-injection-myth-reference-passing/ makalesini okumalısınız (@megadan tarafından belirtilmiştir) , Demeter Yasasına (LoD) veya en az bilgi ilkesine çok dikkat ederek .


Hizmet buluculara yönelik kişisel hoşgörüsüzlüğüm, temel olarak bunları kullanan kodu test etme girişimlerimden kaynaklanmaktadır. Kara kutu testi için, yapıcıyı test etmek için bir örnek yapmak üzere çağırırsınız. Bir istisna derhal veya herhangi bir yöntem çağrısında atılabilir ve sizi eksik bağımlılıklara götürecek hiçbir genel özellik olmayabilir. Kaynağa erişiminiz varsa bu küçük olabilir, ancak yine de En Az Sürpriz İlkesini ihlal ediyor (Singletons ile sık karşılaşılan bir sorun). Bunun bir kısmını hafifleten ve bunun için övgüye değer olan hizmet bulucuya geçmeyi önerdiniz.
Magus

3

Bir kod tabanının bölümlerinin temel taş nesneler veya bir temel sınıf olarak görülmesi nadir değildir, ancak bu, Singleton olarak dikte edilmesi yaşam döngüsünü haklı çıkarmaz.

Programcılar genellikle alternatif bir yaklaşım benimsemek ve açık bir malikânede birbirleri arasında nesne ilişkilerini biraz daha ayrıntılı ve empoze etmek yerine, kolaylık ve saf tembellik aracı olarak Singleton modeline güvenirler.

Öyleyse, bakımı daha kolay olan kendinize sorun.

Benim gibiyseniz, bir başlık dosyasını açmayı ve bir uygulama dosyasındaki yüzlerce kod satırını denetlemek yerine bir nesnenin hangi bağımlılıkları gerektirdiğini görmek için yapıcı argümanlarını ve genel yöntemleri gözden geçirmeyi tercih ediyorum.

Eğer bir nesneyi bir Singleton yaptıysanız ve daha sonra, söz konusu nesnenin birden fazla örneğini destekleyebilmeniz gerektiğinin farkına vardıysanız, bu sınıf kod tabanınızda oldukça yoğun bir şekilde kullandığınız bir şeyse, gerekli olan kapsamlı değişiklikleri hayal edin. Daha iyi bir alternatif, nesne yalnızca bir kez tahsis edilmiş olsa ve birden fazla örneği destekleme ihtiyacı ortaya çıkarsa bile, böyle endişeler olmadan güvenle yapabilirsiniz, bağımlılıkları açık hale getirmektir.

Diğerlerinin de belirttiği gibi, Singleton modelinin kullanılması, modüller arasında genellikle zayıf tasarım ve yüksek uyum gösteren bağlantıyı da engeller. Bu tür bir uyum genellikle istenmez ve bakımı zor olabilecek kırılgan kodlara yol açar.


-1: Bu cevap, singleton desenini yanlış olarak tanımlar ve tüm argümanları, desenin zayıf uygulanmasıyla ilgili sorunları tanımlar. Uygun tekil olan bir arayüz ve (açıkça adresleri Gof bir senaryodur olmayan bekarlık için vardiya, dahil) açıklanan her sorunu ortadan kaldırır. Bir singleton kullanımını yeniden düzenlemek zorsa, açık bir nesne başvurusunun kullanımını yeniden düzenlemek daha az değil, daha zor olabilir. Eğer singleton bir şekilde DAHA FAZLA kod bağlanmasına neden olursa, sadece yanlış yapıldı.
Seth Battin

1

Singleton ünlü bir kalıptır, ancak hizmet ettiği amaçları, artılarını ve eksilerini bilmek iyidir.

Hiçbir ilişki yoksa gerçekten mantıklı geliyor .
Bileşeninizi tamamen farklı bir nesneyle (güçlü bir bağımlılık olmadan) kaldırabilir ve aynı davranışa sahip olmayı beklerseniz, singleton iyi bir seçim olabilir.

Öte yandan, yalnızca belirli zamanlarda kullanılan küçük bir işlevselliğe ihtiyacınız varsa , referansları geçmeyi tercih etmelisiniz .

Bahsettiğiniz gibi, singletons'un yaşam boyu kontrolü yoktur. Ancak avantaj, tembel bir başlangıç ​​durumuna sahip olmaları.
Uygulamanız boyunca o singleton'ı aramazsanız, örneklenemez. Ancak, siz tekiller ürettiğinizden ve kullanmadığınızdan şüpheliyim.

Bir bileşen yerine hizmet gibi bir singleton görmelisiniz .

Singletons işe yarıyor, hiçbir zaman bir uygulama kırmadılar. Ancak onların eksiklikleri (verdiğiniz dördü) bir tane yapmamanızın nedenleridir.


1

Motor zaten birçok tekil kullanır. Birisi kullandıysa, o zaman bazılarına aşina olmalı:

Bilmediğiniz, singleton'lardan kaçınılması gereken sebep değil.

Singleton'ın gerekli veya kaçınılmaz olmasının birçok nedeni vardır. Oyun çerçeveleri genellikle tekilleri kullanır, çünkü sadece tek bir durumsal donanıma sahip olmanın kaçınılmaz bir sonucudur. Bu donanımları kendi kontrol elemanlarının birden fazla örneği ile kontrol etmek istemenin hiçbir anlamı yoktur. Grafik yüzeyi harici bir durumsal donanımdır ve yanlışlıkla grafik alt sisteminin ikinci bir kopyasını başlatmak felaketten başka bir şey değildir, çünkü şimdi iki grafik alt sistemi birbirlerini kontrol edemeyecekleri ve birbirlerinin üzerine yazabilecekleri birbirleriyle savaşacaklardır. Aynı şekilde, olay kuyruğu sistemiyle, fare olaylarını tanımlayıcı olmayan bir biçimde kimin kazandığı üzerine savaşacaklar. Bunlardan yalnızca birinin bulunduğu devlet dışı bir dış donanım ile uğraşırken, singleton, çatışmaları önlemek için kaçınılmazdır.

Singleton'ın duyarlı olduğu bir başka yer ise Cache yöneticileridir. Önbellek özel bir durumdur. Hayatta kalmak ve sonsuza dek yaşamak için Singletons ile aynı teknikleri kullansalar bile bir Singleton olarak görülmemeliler. Önbellekleme hizmetleri şeffaf bir hizmettir, programın davranışını değiştirmeleri beklenmez, bu nedenle önbellek hizmetini boş bir önbellekle değiştirirseniz, programın yalnızca daha yavaş çalışması dışında çalışmaya devam etmesi gerekir. Önbellek yöneticilerinin tekil kurallara istisna olmasının ana nedeni, uygulamanın kendisini kapatmadan önce bir önbellek hizmetini kapatmanın bir anlam ifade etmemesidir. singleton.

Bunlar, bu hizmetlerin tekil olması için iyi nedenlerdir. Ancak, singleton'ların olmasının iyi sebeplerinden hiçbiri, listelediğiniz sınıflara uygulanmaz.

Çünkü onlara oyunumda çok farklı yerlerde ihtiyacım olacak ve paylaşılan erişim çok kullanışlı olurdu.

Bunlar singletonların nedeni değil. Bunlar küresellerin sebepleri. Ayrıca, çeşitli sistemlerin etrafından çok şey geçirmeniz gerekirse, zayıf bir tasarımın işaretidir. Etrafı dolaşmak zorunda olmak, iyi bir OO tasarımı ile önlenebilecek olan yüksek birleşme olduğunu gösterir.

Sadece görevinizde Singletons olması gerektiğini düşündüğünüz sınıfların listesine bakarken, bunların yarısının gerçekten singleton olmaması gerektiğini, diğer yarısının da ilk başta orada olmaması gerektiğini söyleyebildiğini söyleyebilirim. Nesneleri dolaştırmanız gereken, singletonlar için gerçek iyi kullanım durumlarından ziyade uygun kapsülleme eksikliğinden kaynaklanıyor gibi görünmektedir.

Sınıflarınıza birazcık bakalım:


PlayerData (score, lives, ...)
LevelData (parameters per levels and level packs)
GameData (you may obtain some data from server to configure the game)

Sınıfların isimlerinden, bu sınıfların Anemic Domain Model antipattern gibi koktuğunu söyleyebilirim . Anemik nesneler genellikle çevrilmesi gereken birçok bağlantıya neden olur ve bu da eşleşmeyi arttırır ve kodun geri kalanını hantal hale getirir. Ayrıca, anemik sınıf, ayrıntıları kapsüllemek için nesne yönelimini kullanmaktan ziyade muhtemelen hala prosedürsel olarak düşündüğünüzü gizler.


IAP (for in purchases)
Ads (for showing ads)

Neden bu sınıfların tekil olması gerekiyor? Bana göre bunların kısa süren sınıflar olması gerektiği, kullanıcının satın alma işlemini bitirdiğinde veya reklamların gösterilmesi gerekmediğinde gerektiğinde ortaya çıkarılması ve kaldırılması gerektiği ortaya çıktı.


EntityComponentSystemManager (mananges entity creation and manipulation)

Başka bir deyişle, bir yapıcı ve hizmet katmanı? Bu sınıf niçin net bir sınırları yok, ne de bir amacı yok.


PlayerProgress (passed levels, stars)

Oyuncu neden ilerleyişini Oyuncu sınıfından ayırıyor? Player sınıfı, kendi ilerlemesini nasıl takip edeceğini bilmelidir, ilerleme takibini, sorumluluk ayrımı için Player sınıfından farklı bir sınıfta uygulamak istiyorsanız, PlayerProgress Player'ın arkasında olmalıdır.


Box2dManager (manages the physics world)

Bu sınıfın gerçekte ne yaptığını bilmeden bu konuda daha fazla yorum yapamam, ancak bir şey açıktır ki, bu sınıfın kötü adlandırılmış olduğu açıktır.


Analytics (for collecting some analytics)
SocialConnection (Facebook and Twitter login, share, friend list, ...)

Bu, Singleton'ın makul olabileceği tek sınıf gibi görünüyor, çünkü sosyal bağlantı nesneleri aslında sizin nesneleriniz değil. Sosyal bağlantılar, uzak bir serviste yaşayan harici nesnelerin gölgesidir. Başka bir deyişle, bu bir çeşit önbellek. Sadece önbellekleme bölümünü harici servisin servis bölümü ile net bir şekilde ayırdığınızdan emin olun, çünkü ikinci bölümün bir singleton olması gerekmez.

Bu sınıfların örneklerini iletmekten kaçınmanın bir yolu ileti iletisini kullanmaktır. Bu sınıfların örneklerine doğrudan bir çağrı yapmak yerine, bunun yerine, senkronize olmayan bir şekilde Analytic ve SocialConnection servisine gönderilen bir mesaj gönderirsiniz ve bu servisler bu mesajları almak ve mesaj üzerinde hareket etmek için abone olunur. Olay kuyruğu zaten bir tekil olduğundan, aramayı sürtünerek, bir tekille iletişim kurarken gerçek bir örneği geçme gereksinimini ortadan kaldırırsınız.


-1

Bana Singletons her zaman kötü.

Mimarlığımda oyun sınıfının yönettiği bir GameServices koleksiyonu oluşturdum. Gerektiği gibi bu koleksiyona ekleme ve çıkarma arama yapabilirim.

Global kapsamda bir şey söyleyerek temelde yukarıda vermiş olduğunuz örneklerde "bu acılama tanrıdır ve usta yoktur" diyorsunuz, bunların çoğunun ya yardımcı sınıflar ya da GameServices olduğunu söyleyebilirim ki bu durumda oyun onlardan sorumlu olacaktır.

Ama bu sadece motorumdaki tasarımım, durumunuz farklı olabilir.

Daha doğrudan koymak ... Tek gerçek singleton, kodun her bölümüne ait olan oyundur.

Bu cevap, sorunun öznel doğasına dayanıyor ve tamamen benim görüşüme dayanıyor, buradaki tüm geliştiriciler için doğru olmayabilir.

Düzenleme: İstenildiği gibi ...

Tamam şu an kafamdan geliyor, çünkü kodum şu anda önümde değil ama esasen herhangi bir oyunun temelinde gerçek bir singleton olan Oyun sınıfı ... olması gereken!

Ben de aşağıdakileri ekledim ...

class Game
{
   IList<GameService> Services;

   public T GetService<T>() where T : GameService
   {
       return Services.FirstOrDefatult(s => s is T);
   }
}

Şimdi ayrıca tüm programdaki tüm singletonlarımı içeren (statik olan) bir sistem sınıfım (statik) var (çok az oyun ve yapılandırma seçenekleri ve bununla ilgili olanlar var) ...

public static class Sys
{
    // only the main game assembly can set this (done by the game ctor)
    // anything can get
    public static Game Game { get; internal set; }
}

Ve kullanım ...

Her yerden, bir şey yapabilirim.

var tService = Sys.Game.getService<T>();
tService.Something();

Bu yaklaşım, oyunumun tipik olarak "singleton" olarak kabul edilebilecek şeyler "sahibi olduğum" anlamına gelir ve temel GameService sınıfını istediğim gibi uzatabilirim. Oyunumun belirli durumlar için gerektiği gibi uygulayan hizmetleri kontrol edip çağırdığı IUpdateable gibi arayüzlerim var.

Ayrıca daha belirli sahne senaryoları için diğer hizmetleri alan / genişleten hizmetlere de sahibim.

Örneğin ...

Fizik simülasyonlarımı idare eden bir Fizik servisim var ancak sahneye bağlı olarak fizik simülasyonu biraz farklı davranışlar gerektirebilir.


1
Oyun hizmetleri sadece bir kez başlatılmamalı mı? Eğer öyleyse, bu, sadece doğru bir şekilde uygulanmış bir singletondan daha kötü olan sınıf düzeyinde uygulanmayan bir singleton modelidir.
GameAlchemist

2
@Wardy Ne yaptığınızı tam olarak anlamadım ama açıkladığım Singleton Cephe gibi görünüyor ve bir GOD nesnesi olmalı, değil mi?
Narek

10
Bu sadece oyun seviyesinde uygulanan bir Singleton modeli. Bu yüzden, temel olarak en ilginç yanı, Singleton kullanmıyormuş gibi davranmanıza izin vermektir. Patronunuz desen karşıtı kiliseden ise faydalıdır.
GameAlchemist

2
Bunun Singletons kullanmaktan ne kadar etkili olduğunu bilmiyorum. Bu tür mevcut tek servisinize ne kadar özel olarak eriştiğinizin tek farkı bu değil mi? Yani var tService = Sys.Game.getService<T>(); tService.Something();, getServiceparçayı atlamak ve doğrudan erişmek yerine ?
Christian

1
@Hristiyan: Gerçekten de, Servis Bulucu antipattern tam olarak budur. Görünüşe göre bu topluluk hala önerilen bir tasarım deseni olduğunu düşünüyor.
Magus

-1

Singleton'un rakiplerinin çoğu zaman göz önünde bulundurmadığı temel bir singleton eliminasyon bileşeni, singletons örnek değerlerine yol açtığında nesnelerin enkapsüle ettiği çok daha karmaşık durumla başa çıkmak için ekstra bir mantık ekliyor. Aslında, bir singletonu bir değişkenle değiştirdikten sonra bir nesnenin durumunu tanımlamak bile zor olabilir, ancak singletonları örnek değişkenlerle değiştiren programcılar bununla başa çıkmak için hazırlanmalıdır.

Örneğin, Java adlı için, karşılaştırın HashMap.NET en ile Dictionary. Her ikisi de oldukça benzer, ancak önemli bir farkları var: Java HashMapkullanımı zor kodlanmış equalsve hashCode(etkin bir şekilde bir singleton karşılaştırıcı kullanıyor), .NET'ler bir yapıcı parametresi Dictionaryörneğini kabul edebilir IEqualityComparer<T>. Korumanın çalışma zamanı maliyeti IEqualityComparerasgari düzeydedir ancak getirdiği karmaşıklık değildir.

Her Dictionaryörnek bir kapsül IEqualityCompareriçerdiğinden, durumu yalnızca gerçekten içerdiği anahtarlar ve bunlarla ilişkili değerler arasındaki bir eşleme değil, bunun yerine anahtarlar ve karşılaştırıcı ve bunlarla ilişkili değerlerin tanımladığı eşdeğerlik kümeleri arasındaki bir eşlemedir . İki durum olursa d1ve d2bir Dictionaryaynı etmek tutma referanslar IEqualityComparer, yeni bir örneğini üretmek mümkün olacaktır d3herhangi şekilde x, d3.ContainsKey(x)eşit olacaktır d1.ContainsKey(x) || d2.ContainsKey(x). Bununla birlikte, farklı keyfi eşitlik karşılaştırıcılarına referanslar verebilir d1ve d2referanslar alabilirse, genel olarak koşulun geçerli olmasını sağlamak için bunları birleştirmenin bir yolu olmayacaktır.

Singleton'ları ortadan kaldırmak için örnek değişkenler eklemek, ancak bu örnek değişkenler tarafından ima edilebilecek olası yeni durumları tam olarak hesaba katmamak, singleton ile olduğundan daha kırılgan hale gelen kod oluşturabilir. Her nesne örneğinin ayrı bir alanı varsa, ancak hepsi aynı nesne örneğini tanımlamazsa işler kötü şekilde arızalanırsa, o zaman tüm yeni alanların satın aldığı şeylerin yanlış gidebilmesi için artan sayıda yol vardır.


1
Bu kesinlikle tartışmanın ilginç bir yönü olsa da, aslında OP'nin sorduğu soruyu ele aldığını sanmıyorum.
Josh

1
@JoshPetrie: Orijinal yazıdaki yorumlar (örneğin Magus), singleton kullanmaktan kaçınmak için referansları taşıma zamanının maliyetinin çok iyi olmadığını öne sürdü. Dolayısıyla, her nesnenin tekil tonlardan kaçınmak amacıyla referansları kapsama almasının anlamsal maliyetlerini alakalı olarak değerlendiririm . Kişi ucuz ve kolay bir şekilde kaçınılabileceği durumlarda singletonlardan kaçınmalıdır, ancak açıkça bir singleton gerektirmeyen, ancak bir şeyin birden fazla örneği varsa, bir singleton kullanan koddan daha kötü olan kod kırılabilir.
supercat

2
Cevaplar doğrudan soruya cevap verdikleri yorumları ele almak değildir.
ClassicThunder

@ ClassicThunder: Düzenlemeyi daha çok beğeniyor musunuz?
supercat
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.