PHP'de veritabanı erişimi olan singletonlar için bir kullanım durumu var mı?


138

MySQL veritabanına PDO üzerinden erişiyorum. Veritabanına erişim ayarlıyorum ve ilk denemem aşağıdakileri kullanmaktı:

Düşündüğüm ilk şey global:

$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'root', 'pwd');

function some_function() {
    global $db;
    $db->query('...');
}

Bu kötü bir uygulama olarak kabul edilir. Küçük bir aramadan sonra, Singleton kalıbıyla sonuçlandım.

"bir sınıfın tek bir örneğinin olması gereken durumlar için geçerlidir."

Kılavuzdaki örneğe göre, bunu yapmalıyız:

class Database {
    private static $instance, $db;

    private function __construct(){}

    static function singleton() {
        if(!isset(self::$instance))
            self::$instance = new __CLASS__;

        return self:$instance;
    }

    function get() {
        if(!isset(self::$db))
            self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd')

        return self::$db;
    }
}

function some_function() {
    $db = Database::singleton();
    $db->get()->query('...');
}

some_function();

Bunu yapabildiğim zaman neden nispeten büyük sınıfa ihtiyacım var?

class Database {
    private static $db;

    private function __construct(){}

    static function get() {
        if(!isset(self::$db))
            self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd');

        return self::$db;
    }
}

function some_function() {
    Database::get()->query('...');
}

some_function();

Bu sonuncusu mükemmel çalışıyor ve $dbartık endişelenmeme gerek yok.

Nasıl daha küçük bir singleton sınıfı oluşturabilirim veya PHP'de eksik olduğum singletonlar için bir kullanım durumu var mı?


Bu ilgili soruda çok fazla kaynak ve tartışma var: 'Teklitonlarda bu kadar kötü olan ne?'
FruitBreak

Yanıtlar:


80

Tamam, kariyerime ilk başladığımda bir süredir merak ettim. Farklı şekillerde uyguladı ve statik sınıflar kullanmamayı seçmek için iki neden ortaya çıktı, ancak bunlar oldukça büyük.

Birincisi, çoğu zaman asla birden fazla örneğiniz olmayacağından emin olduğunuz bir şey olduğunu, sonunda bir saniyeniz olduğunu göreceksiniz. İkinci bir monitör, ikinci bir veritabanı, ikinci bir sunucu olabilir - her neyse.

Bu olduğunda, statik bir sınıf kullandıysanız, singleton kullanmış olduğunuzdan çok daha kötü bir refactor içindesiniz. Singleton kendi içinde iffy bir desendir, ancak oldukça kolay bir şekilde akıllı bir fabrika modeline dönüşür - hatta çok fazla sorun olmadan bağımlılık enjeksiyonuna dönüştürülebilir. Örneğin, singleton'unuz getInstance () aracılığıyla elde edilmişse, bunu getInstance (databaseName) için kolayca değiştirebilir ve birden fazla veritabanına izin verebilirsiniz - başka kod değişikliği yapmazsınız.

İkinci konu testtir (Ve dürüst olmak gerekirse, bu ilk sorunla aynıdır). Bazen veritabanınızı sahte bir veritabanı ile değiştirmek istersiniz. Aslında bu, veritabanı nesnesinin ikinci bir örneğidir. Bu, statik sınıflarla tek bir tonda olduğundan çok daha zordur, statik sınıftaki her yöntemi (bazı dillerde çok zor olabilir) sadece getInstance () yöntemini taklit etmeniz gerekir.

Bu gerçekten alışkanlıklara dönüşüyor - ve insanlar "Globals" in kötü olduğunu söylediklerinde, bunu söylemek için çok iyi nedenleri var, ama problemi kendiniz vuruncaya kadar her zaman açık olmayabilir.

Yapabileceğiniz en iyi şey sormak (yaptığınız gibi) sonra bir seçim yapmak ve kararınızın sonuçlarını gözlemlemektir. Kodunuzun zaman içindeki gelişimini yorumlayacak bilgiye sahip olmak, ilk etapta doğru yapmaktan çok daha önemlidir.


15
Singletonların DI'ye güzel bir şekilde düştüğünü söylüyorsunuz, ancak getInstance(databaseName)kodunuz boyunca küresel bir örnek havuzuna hala saçılma referanslarına örnek değil misiniz? Çağıracak kod getInstance, örnek (ler) in istemci koduyla enjekte edilmeli getInstanceve ilk etapta aramaya gerek kalmamalıdır .
Vousden

1
@ Vousden Doğru, bu bir tür boşluk. Gerçekten DI değil, ama oldukça yakın olabilir. Örneğin, getInstance (desteklenenDatabase) ve döndürülen örnek, hangi veritabanının aktarıldığına bağlı olarak hesaplandıysa ne olacak? Mesele, insanları hazır olana kadar DI çerçevesi ile korkutmaktan kaçınmaktır.
Bill K

320

Teklitonlar PHP'de çok az - hayır demek olmasa da - kullanmazlar.

Nesnelerin paylaşılan bellekte yaşadığı dillerde, Singletons bellek kullanımını düşük tutmak için kullanılabilir. İki nesne oluşturmak yerine, genel olarak paylaşılan uygulama belleğinden var olan bir örneğe başvuruyorsunuz. PHP'de böyle bir uygulama belleği yoktur. Bir İstekte oluşturulan bir Singleton tam olarak bu istek için yaşar. Aynı anda yapılan başka bir İstekte oluşturulan bir Singleton hala tamamen farklı bir örnektir. Dolayısıyla, bir Singleton'un iki ana amacından biri burada uygulanamaz.

Ayrıca, uygulamanızda kavramsal olarak yalnızca bir kez var olabilen nesnelerin çoğu, bunu uygulamak için bir dil mekanizması gerektirmez. Yalnızca bir örneğe ihtiyacınız varsa , başka bir örneği başlatmayın . Yalnızca başka bir örneğiniz olmadığında , örneğin ikinci bir örnek oluştururken yavru kedi öldüğünde, bir Singleton için geçerli bir Kullanım Durumunuz olabilir.

Diğer amaç, aynı İstek içindeki bir örneğe genel erişim noktasına sahip olmaktır. Bu istenen gibi görünse de, gerçekten değildir, çünkü küresel kapsamla (herhangi bir küresel ve statik gibi) bir bağlantı oluşturur. Bu, Birim Testini zorlaştırır ve genel olarak uygulamanız daha az bakım yapılabilir. Bunu hafifletmenin yolları vardır, ancak genel olarak, birçok sınıfta aynı örneğe ihtiyacınız varsa, Bağımlılık Enjeksiyonunu kullanın .

PHP'de Singletons için slaytlarıma bakın - Neden kötüdürler ve ek bilgi için bunları uygulamalarınızdan nasıl kaldırabilirsiniz .

Singleton deseninin mucitlerinden Erich Gamma bile bugünlerde bu modelden şüphe ediyor:

"Singleton'u bırakmaktan yanayım. Kullanımı neredeyse her zaman bir tasarım kokusudur"

daha fazla okuma

Yukarıdakilerden sonra, hala karar vermek için yardıma ihtiyacınız varsa:

Singleton Karar Diyagramı


1
@ Gordon evet. Ve istekler arasında nesneleri korumak mümkün olsa bile, Singletons hala birkaç SOLID ilkesini ihlal ediyor ve Global State'i tanıttı.
Gordon

4
Akışa aykırı olduğum için üzgünüm, ancak 42 ctor parametresi (veya 42 setFoo () ve setBar () çağrısı yapmak için gerekli sınıflara sahip değilseniz, Singleton'un kullanıldığı soruna gerçekten bir çözüm değildir. iş). Evet, bazı uygulamalar maalesef bu birleştirilmiş olmalı ve birçok harici şeye bağlı olmalıdır. PHP bir yapıştırıcı dilidir ve bazen birlikte yapıştırılacak çok şey vardır.
StasM

14
@StasM 42 ctor parametresine sahipseniz veya çok sayıda ayarlayıcıya ihtiyacınız varsa yanlış yapıyorsunuz. Temiz Kod Görüşmelerini lütfen izleyin. Üzgünüm, bunu başka bir zaman açıklamaktan rahatsız olmazsam. Daha fazla bilgi için PHP sohbet odasında soru sormaktan çekinmeyin.
Gordon

@Gordon Php sohbet odası nerede?
user658182

21

PHP'de singletona kimin ihtiyacı var?

Tek tektonlara yapılan itirazların neredeyse hepsinin teknik açıdan geldiğine dikkat edin - ama aynı zamanda kendi kapsamlarında ÇOK sınırlıdır. Özellikle PHP için. İlk olarak, singletonları kullanmanın bazı nedenlerini listeleyeceğim ve sonra singletons kullanımıyla ilgili itirazları analiz edeceğim. İlk olarak, onlara ihtiyaç duyan insanlar:

- Birçok farklı ortamda kullanılacak büyük bir çerçeve / kod tabanını kodlayan kişilerin, istemcilerden / patronlardan çok farklı, değişen, hatta kaprisli talepleri yerine getirme gereği ile önceden var olan farklı çerçeveler / kod tabanlarıyla çalışması gerekecektir. / yönetim / birim liderleri yapar.

Bakın, tekil desen kendiliğinden kapsayıcı. Tamamlandığında, bir singleton sınıfı, dahil ettiğiniz herhangi bir kod boyunca katıdır ve yöntemlerini ve değişkenlerini nasıl oluşturduğunuz gibi davranır. Ve verilen bir istekte her zaman aynı nesnedir. İki farklı nesne olmak için iki kez oluşturulamadığından, tek bir nesnenin koddaki herhangi bir noktada ne olduğunu bilirsiniz - singleton iki, üç farklı, eski, hatta spagetti kod tabanına yerleştirilse bile. Bu nedenle, geliştirme amaçları açısından kolaylaştırır - bu projede çalışan birçok kişi olsa bile, herhangi bir kod tabanında bir noktada başlatılmış bir singleton gördüğünüzde, bunun ne olduğunu, ne yaptığını, nasıl olduğunu biliyorsunuz geleneksel sınıf olsaydı, o nesnenin ilk nerede yaratıldığını takip etmeniz gerekirdi, koddaki o noktaya kadar hangi yöntemler çağrıldı ve özel durumu. Ancak, orada bir singleton bırakın ve kodlama sırasında uygun hata ayıklama ve bilgi yöntemlerini ve izlemeyi bıraktıysanız, tam olarak ne olduğunu biliyorsunuzdur. Bu nedenle, daha önce farklı felsefelerle yapılmış olan veya hiç temasa sahip olmadığınız kişiler tarafından yapılan kodu entegre etme zorunluluğu ile farklı kod tabanlarıyla çalışmak zorunda olan kişilerin işini kolaylaştırır. (yani, satıcı-proje-şirket-ne olursa olsun artık, hiçbir destek yok). farklı kodlarla çalışmak zorunda olan insanlar için, daha önce farklı felsefelerle yapılan ya da hiç temasa sahip olmadığınız kişiler tarafından yapılan kodun bütünleştirilmesi zorunluluğunu kolaylaştırır. (yani, satıcı-proje-şirket-ne olursa olsun artık, hiçbir destek yok). farklı kodlarla çalışmak zorunda olan insanlar için, daha önce farklı felsefelerle yapılan ya da hiç temasa sahip olmadığınız kişiler tarafından yapılan kodun bütünleştirilmesi zorunluluğunu kolaylaştırır. (yani, satıcı-proje-şirket-ne olursa olsun artık, hiçbir destek yok).

- Üçüncü taraf API'ları , hizmetleri ve web siteleriyle çalışması gereken kişiler .

Daha yakından bakarsanız, bu önceki durumdan çok farklı değildir - üçüncü taraf API'ları, hizmetleri, web siteleri, üzerinde hiçbir kontrolünüz olmadığı harici, yalıtılmış kod tabanları gibidir. Her şey olabilir. Böylece, tek bir oturum / kullanıcı sınıfıyla, OpenID , Facebook , Twitter ve daha birçok üçüncü taraf sağlayıcıdan HERHANGİ bir oturum / yetkilendirme uygulamasını yönetebilirsiniz - ve bunları aynı anda SAME singleton nesnesinden yapabilirsiniz - kolayca erişilebilir, bilinen bir durumda, hangi kodu taktığınız herhangi bir noktada. Kendi web sitenizde / uygulamanızda SAME kullanıcısı için birden fazla farklı üçüncü taraf API / hizmetine birden fazla oturum oluşturabilir ve bunlarla ne yapmak isterseniz yapabilirsiniz.

Tabii ki, tüm bunlar normal sınıflar ve nesneler kullanarak geleneksel yöntemlerle ton olabilir - buradaki yakalama, singleton daha düzenli, daha düzenli ve bu nedenle bu tür durumlarda geleneksel sınıf / nesne kullanımına kıyasla yönetilebilir / test edilebilir daha kolaydır.

- Hızlı gelişim yapması gereken insanlar

Tek tektonların küresel benzeri davranışı, tek tek koleksiyonlar içeren bir çerçeveye sahip bir çerçeveyle her türlü kodu oluşturmayı kolaylaştırır, çünkü tek tek sınıflarınızı iyi yapılandırdığınızda, yerleşik, olgun ve set yöntemleri kolayca kullanılabilir ve her yerde, her zaman, tutarlı bir şekilde kullanılabilir. Sınıflarınızı olgunlaştırmak biraz zaman alır, ancak bundan sonra kaya gibi sağlam ve tutarlı ve kullanışlıdır. Tek birtonda ne istersen yapıyorsun birçok yönteme sahip olabilirsin ve bu, nesnenin bellek ayak izini artırabilse de, hızlı geliştirme için gereken zamandan çok daha fazla tasarruf getiriyor - belirli bir örnekte kullanmadığın bir yöntem bir uygulama başka bir entegre uygulamada kullanılabilir ve sadece istemci / patron / proje yöneticisinin birkaç değişiklikle sorduğu yeni bir özelliği tokatlayabilirsiniz.

Kaptın bu işi. Şimdi, yararlı olan bir şeye karşı tektonlara ve kutsal haçlı seferine itirazlara geçelim :

- En çok itiraz, testi zorlaştırmasıdır.

Ve gerçekten, bir ölçüye göre, uygun önlemleri alarak ve hata ayıklama rutinlerini tek bir hata ayıklayacağınızın farkına vararak tek tek tonlarınıza kodlayarak kolayca azaltılabilse bile. Ama bakın, bu, orada olan HERHANGİ diğer kodlama felsefesi / yöntemi / modelinden çok farklı değil - sadece, tek tonlar nispeten yeni ve yaygın değil, bu nedenle mevcut test yöntemleri onlarla karşılaştırılabilir olarak sona eriyor. Ancak bu, programlama dillerinin herhangi bir yönünden farklı değildir - farklı stiller farklı yaklaşımlar gerektirir.

Bu itirazın düzleştiği bir nokta, geliştirilen uygulamaların 'test etme' nedeni olmadığı ve testin uygulama geliştirmeye giden tek aşama / süreç olmadığı gerçeğini göz ardı etmektedir. Uygulamalar üretim kullanımı için geliştirilmiştir. Ve 'tek tektonlara ihtiyaç duyan' bölümünde açıkladığım gibi, tek tektonlar, bir kodun birçok farklı kod tabanı / uygulama / üçüncü taraf hizmetiyle İLE ve İÇERİĞİ yapmak zorunda olmanın karmaşıklığından BÜYÜK bir anlaşma kesebilir. Test sırasında kaybedilebilecek zaman, geliştirme ve devreye almada kazanılan zamandır. Bu, özellikle üçüncü taraf kimlik doğrulama / uygulama / entegrasyon çağında yararlıdır - Facebook, Twitter, OpenID, daha fazlası ve bir sonraki adımın kim olduğunu bilebilir.

Anlaşılabilir olmasına rağmen - programcılar kariyerlerine bağlı olarak çok farklı koşullarda çalışırlar. Ve farklı büyüklüklerde, tanımlanmış departmanları olan, rahat bir şekilde farklı, tanımlanmış yazılım / uygulamalar eğilimi gösteren ve bütçe kesintilerinin / işten çıkarmanın yaklaşan kıyameti olmadan çalışan insanlar için ve bununla birlikte, ucuz / hızlı / güvenilir bir moda, singletonlar çok gerekli görünmeyebilir. Ve ZATEN sahip oldukları şey için sıkıntı / engel bile olabilir.

Ancak, 'çevik' gelişimin kirli hendeklerinde çalışması gereken, müşteri / yönetici / projelerinden birçok farklı talep (bazen mantıksız) uygulamak zorunda olanlar için, singletonlar daha önce açıklanan nedenlerden dolayı tasarruflu bir lütuftur.

- Başka bir itiraz, bellek ayak izinin daha yüksek olması

Her istemciden gelen her istek için yeni bir singleton bulunacağı için bu PHP için bir itiraz olabilir. Kötü yapılandırılmış ve kullanılmış tek tonlarda, herhangi bir noktada uygulama tarafından çok sayıda kullanıcıya hizmet veriliyorsa, uygulamanın bellek alanı daha yüksek olabilir.

Yine de bu, şeyleri kodlarken uygulayabileceğiniz HERHANGİ bir yaklaşım için geçerlidir. Sorulması gereken sorular, bu tektonlar tarafından tutulan ve işlenen yöntemler, veriler gereksiz midir? Çünkü, uygulamanın aldığı isteklerin birçoğunda gerekliyse, tekilton kullanmasanız bile, bu yöntemler ve veriler kodunuz aracılığıyla bir şekilde veya başka bir şekilde uygulamanızda mevcut olacaktır. Yani, kod işleme içine 1/3 geleneksel bir sınıf nesnesi başlattığınızda ve bunu 3/4 içine imha ettiğinizde, ne kadar bellek tasarrufu yapacağınız sorusu haline gelir.

Bakın, bu yolla konulduğunda, soru oldukça önemsiz hale gelir - gereksiz yöntemler, kodunuzdaki nesnelerde HERHANGİ bir şekilde tutulan veriler olmamalıdır - tekliton kullanmanızdan bağımsız olarak. Yani, tektonlara yapılan bu itiraz gerçekten komik olur, kullandığınız sınıflardan yaratılan nesnelerde gereksiz yöntemler, veriler olacağını varsayar.

- 'Birden çok veritabanı bağlantısını sürdürmeyi imkansız / zorlaştırıyor' gibi bazı geçersiz itirazlar

Herkesin birden fazla veritabanı bağlantısı, birden çok veritabanı seçimi, birden çok veritabanı sorgusu, belirli bir singletondaki birden çok sonuç kümesini tek bir değişkente tuttuğu sürece, bu itirazı anlamaya başlayamıyorum ihtiyaç vardır. Bu, dizilerde tutmak kadar basit olabilir, ancak bunu gerçekleştirmek için kullanmak istediğiniz herhangi bir yöntemi icat edebilirsiniz. Ancak en basit durumu, değişkenlerin ve dizilerin belirli bir singletonda kullanımını inceleyelim:

Aşağıdakilerin belirli bir veritabanı singletonunun içinde olduğunu düşünün:

$ this -> connections = dizi (); (yanlış sözdizimi, sadece resmi vermek için böyle yazdım - değişkenin doğru beyanı genel $ connections = array (); ve kullanımı $ this-> connections ['connectionkey'] doğal olarak)

Bu şekilde bir dizide herhangi bir zamanda birden çok bağlantı kurabilir ve saklayabilirsiniz. Aynı şey sorgular, sonuç kümeleri vb. İçin de geçerlidir.

$ this -> query (QUERYSTRING, 'queryname', $ this-> connections ['partikül bağlantı']);

Bu, yalnızca seçili bir bağlantıyla seçilen bir veritabanına sorgu yapabilir ve yalnızca

$ this -> sonuç

'queryname' anahtarıyla dizi. Tabii ki, sorgu yönteminizin bunun için kodlanmış olması gerekir - ki bu önemsizdir.

Bu, neredeyse sonsuz sayıda (elbette kaynak sınırlarının izin verdiği ölçüde) farklı veritabanı bağlantılarını ve sonuç kümelerini ihtiyacınız olduğu kadar korumanızı sağlar. Ve herhangi bir kod tabanında bu singleton sınıfının örneklendiği herhangi bir noktada HERHANGİ bir kod parçası için kullanılabilirler.

DERSİN doğal olarak, sonuç kümelerini ve bağlantıları gerekli olmadığında serbest bırakmanız gerekir - ancak bu söylenmeden gider ve bu, singletonlara veya diğer herhangi bir kodlama yöntemine / stiline / kavramına özgü değildir.

Bu noktada, üçüncü taraf uygulamalara veya hizmetlere aynı tektonda birden çok bağlantıyı / durumu nasıl koruyabileceğinizi görebilirsiniz. Çok farklı değil.

Uzun lafın kısası, sonunda, singleton kalıpları, programlanacak başka bir yöntem / stil / felsefe ve doğru yerde, doğru şekilde kullanıldıklarında HERHANGİ kadar faydalıdırlar. Bu hiçbir şeyden farklı değil.

Tektonların dayatıldığı makalelerin çoğunda, 'küresellerin' kötülük olduğunu da görebilirsiniz.

Kabul edelim - Düzgün kullanılmayan, kötüye kullanılan, kötüye kullanılan her şey kötüdür. Bu herhangi bir dil, herhangi bir kodlama konsepti ve herhangi bir yöntemle sınırlı değildir. Birinin 'X kötüdür' gibi battaniye ifadeleri çıkardığını gördüğünüzde, bu makaleden kaçın. Şansı, sınırlı bir bakış açısının ürünüdür - bakış açısı belirli bir şeydeki yılların deneyiminin sonucu olsa bile - genellikle belirli bir tarzda / yöntemde - tipik entelektüel muhafazakârlıkta çok fazla çalışmanın sonucu olarak ortaya çıkar.

Bunun için 'küreseller kötülükten' iframe'ler kötüdür 'gibi sonsuz örnekler verilebilir. Yaklaşık 10 yıl önce, herhangi bir uygulamada iframe kullanımını önermek bile sapkınlıktı. Sonra Facebook, her yerde iframe geliyor ve neler olduğuna bakın - iframe'ler artık o kadar kötü değil.

Hala inatla 'kötü' olduklarında ısrar eden insanlar var - ve bazen de iyi bir nedenden ötürü - ama gördüğünüz gibi, bu ihtiyacı dolduran ve iyi çalışan iframe'lerin doldurulması gerekiyor ve bu nedenle tüm dünya devam ediyor.

Bir programcı / kodlayıcı / yazılım mühendisinin en önemli varlığı özgür, açık ve esnek bir zihindir.


2
-1. Açık ve esnek bir zihne sahip olmanın herhangi bir geliştirici için bir zorunluluk olduğunu kabul etsem de, Singleton'un bir Antipattern olduğu anlamına gelmez. Yukarıdaki cevap, Singleton'ın doğası ve etkileri hakkında o kadar çok yanlış ifade ve yanlış sonuç içeriyor.
Gordon

-1. Birçok tektonla ilk elden bir çerçeve yaşamam gerekiyordu ve otomatik test mümkün değil. Bir tarayıcıda deneme yanılma yoluyla her şeyi manuel olarak test etmem gerekiyor. Bazı hatalar kod inceleme ile önlenebilir (yazım, sözdizimi hataları), ancak işlevsel hatalar genellikle gizlenir. Bu test, birim testlerden çok daha fazla zaman gerektirir. Birim testleri ile şunu söyleyebilirim: Bu sınıf tek başına çalışır, hata başka bir yerde olmalıdır. Hata ayıklama olmadan sıkıcı.
Jim Martens

Çerçeve, günlük kaydı ve hata izlemede bulunmalıydı. Ayrıca, tek başına düzgün çalışan bir sınıf, daha geniş bir uygulamaya konduğunda tek bir formda da düzgün çalışacaktır. Yani bu durumda kırılan şey, o singleton ile etkileşime giren başka bir sınıf ya da işlev olacaktır. Bu, büyük bir uygulamanın içindeki normal hata izlemeden farklı değildir. Hangi uygun günlük kaydı olmadan uygulama oldukça zor.
unity100

Yanlış. Tek ton ton kesinlikle kötüdür, çünkü Testing-HELL oluşturur. :-) Ancak, uygulama başına bir tek ton iyi olabilir. Örneğin: birleşik bir kayıt özelliği olarak - tüm uygulamalara uygulamak (bazı eski kodlar dahil).
Filip OvertoneSinger Rydlo

“Test sırasında kaybedilebilecek zaman ...” Bu gerçekten çok kötü bir uygulama ve düşünme şeklidir. Tüm bu eski uygulamalar bu düşünceyle geliştirildi ve onları korumak imkansız hale geldi, böylece yeniden yazılmaları gerekiyordu. Test yoksa, yeni bir özellik geliştirildiğinde ve sistemin başka bir bölümünde bir şey kırıldığında zaman kaybedilecektir. Zaman uygulamasında güven vb kaybetti, ayıklama düzgün bu özelliği kullanabilirsiniz kullanıcılar tarafından kaybedilen zaman kaybettik
bogdancep

15

Singletons, birçok kişi tarafından gerçekten küresel değişkenler yüceltildiği için anti-desen olarak kabul edilir . Uygulamada , bir sınıfın sadece bir örneği olması gereken nispeten az senaryo vardır ; genellikle sadece bir örnek yeterlidir , bu durumda bunu tekil olarak uygulamak tamamen gereksizdir.

Soruyu cevaplamak için, burada tek teklerin aşırı dolu olduğu konusunda haklısınız. Basit bir değişken veya işlev yapar. Bununla birlikte, daha iyi (daha sağlam) bir yaklaşım, küresel değişkenlere olan ihtiyacı tamamen ortadan kaldırmak için bağımlılık enjeksiyonu kullanmak olacaktır .


Ancak Singletons DI'ye çok düzgün bir şekilde bozulabilir, statik sınıflar olamaz, bu da statik sınıflarla ilgili gerçek bir sorundur.
Bill K

@Bill: Çok doğru, ama bu yüzden gevşek fonksiyonlar veya statik yöntemler yerine başlamak için bir DI yaklaşımını savunuyorum :)
Vousden

Bazı dillerde (Java gibi) statik sınıflar (veya statik sınıf yöntemleri) genişletilemez. Böylece gelecekteki geliştiriciler için potansiyel sorunlar yaratırsınız (ya da en iyi ihtimalle daha fazla iş çıkarırsınız). Bu nedenle, bazıları, belirli bir gereksiniminiz olmadığı sürece statik yöntemlerden genellikle kaçınılması gerektiğini önermektedir.
Marvo

8

Örneğinizde, görünüşte değişmeyen tek bir parça ile ilgileniyorsunuz. Bu örnek için, bir Singleton aşırıya kaçabilir ve sadece bir sınıfta statik işlev kullanmak iyi olur.

Daha fazla düşünce: Desenler uğruna desen uygulama örneği yaşıyor olabilirsiniz ve bağırsağınız size açıkladığınız nedenlerle "hayır, yapmanız gerekmiyor" diyor.

AMA: Projenizin büyüklüğü ve kapsamı hakkında hiçbir fikrimiz yok. Bu basit bir kodsa, belki de atın, değişmesi gerekmiyorsa, evet, devam edin ve statik üyeler kullanın. Ancak, projenizin yolu kodlayan bakım için ölçeklendirilmesi veya hazırlanması gerekebileceğini düşünüyorsanız, evet, Singleton desenini kullanmak isteyebilirsiniz.


1
Vay be, sadece yanlış. Farkın bütün mesele (sorunun cevabı), daha sonra ikinci bir örnek eklemek için kodunuzu düzeltmenin ne kadar zor olduğudur. Statik yöntemler kullandıysanız bunu yapmak çok daha zordur. Bu, Globals ile ilgili sorunların tümü değiştiğinde "Globaller sınırlı koşullarınızda iyidir" demek gibidir.
Bill K

@ Fatura K: Sana katılıyorum ve herhangi bir karmaşıklık olsaydı bir singleton kullanırdım. Ama soruyu OP'nin bakış açısıyla cevaplamaya çalışıyordum, evet, sanırım bu çok sınırlı durumda aşırıya kaçmış. Tabii ki mimari veya ölçeklenebilirlik kaygılarını ve bir sürü başka düşünceyi görmezden geldim. Birinin neden her zaman bir singleton kullanması gerektiğine dair bir açıklama ile cevabımda bir uyarı olarak eklemeliydim ... ki bu kesinlikle başkalarından aşağı düşmelere neden olurdu?
Paul Sasik

5

Birincisi, sadece Singleton modelinin pek bir işe yaramadığını söylemek istiyorum. Neden tek bir nesneyi tüm uygulamayı eksiksiz tutmak istesin ki? Özellikle veritabanları için, başka bir veritabanı sunucusuna bağlanmak istersem ne olur? Her seferinde bağlantıyı kesip yeniden bağlanmak zorundayım ...? Neyse ...

Bir uygulamada globalleri kullanmanın birkaç dezavantajı vardır (Singleton modelinin geleneksel kullanımı budur):

  • Birim testi zor
  • Bağımlılık enjeksiyon sorunları
  • Kilitleme sorunları oluşturabilir (çok iş parçacıklı uygulama)

Singleton yerine statik sınıflar kullan, aynı dezavantajlardan bazılarını da sağlar, çünkü singleton'un en büyük sorunu statik getInstanceyöntemdir.

Geleneksel getInstanceyöntemi kullanmadan bir sınıfın sahip olabileceği örnek sayısını sınırlayabilirsiniz :

class Single {

    static private $_instance = false;

    public function __construct() {
        if (self::$_instance)
           throw new RuntimeException('An instance of '.__CLASS__.' already exists');

        self::$_instance = true;
    }

    private function __clone() {
        throw new RuntimeException('Cannot clone a singleton class');
    }

    public function __destruct() {
        self::$_instance = false;
    }

}

$a = new Single;
$b = new Single; // error
$b = clone($a); // error
unset($a);
$b = new Single; // works

Bu, yukarıda belirtilen hususlara ilk olarak yardımcı olacaktır: birim testi ve bağımlılık enjeksiyonu; yine de uygulamanızda sınıfın tek bir örneğinin bulunduğundan emin olun. Örneğin, elde edilen nesneyi kullanmaları için modellerinize (MVC kalıbı) iletebilirsiniz.


5

Çözümünüzün PHP belgelerinde sunulan çözümden nasıl farklı olduğunu düşünün. Aslında, sadece bir "küçük" fark vardır: çözümünüz alıcıyı arayanlara bir PDOörnek sağlarken, dokümanlardaki kişi arayanlara Database::singletonbir Databaseörnek sunar (daha sonra bunu PDOörnek almak için alıcıyı kullanırlar ).

Peki hangi sonuca varıyoruz?

  • Doküman kodunda arayanlar bir Databaseörnek alır. DatabaseSınıf (aslında, maruz bırakabilir gerektiğini size 'bu kadar zahmete gidiyoruz eğer açığa) göre daha zengin ya da daha üst düzey bir arayüz PDOo sarar nesne.
  • Uygulamanızı başka bir (daha zengin) tür döndürecek şekilde değiştirirseniz PDO, iki uygulama eşdeğerdir. Manuel uygulamayı takip etmekten kazanılamaz.

Pratik tarafta, Singleton oldukça tartışmalı bir modeldir. Bunun başlıca nedeni:

  • Aşırı kullanılmış. Acemi programcılar Singleton'u diğer desenlere göre çok daha kolay grok. Daha sonra, yeni problem bilgilerini her yerde uygulamaya devam ederler, eldeki sorun Singleton olmadan daha iyi çözülse bile (bir çekiç tutarken, her şey çivi gibi görünür).
  • Programlama diline bağlı olarak, bir Singleton'u hava geçirmez, sızdıran bir şekilde uygulamak titanik bir görev olduğunu kanıtlayabilir (özellikle gelişmiş senaryolarımız varsa: başka bir singletona bağlı bir singleton, yok edilebilen ve yeniden oluşturulabilen singletonlar, vb. ). C ++ 'da "kesin" Singleton uygulamasını aramaya çalışın, size cesaret ediyorum (Andrei Alexandrescu'nun çığır açan belgelerin çoğunu oluşturan çığır açan Modern C ++ Tasarımına sahibim).
  • Hem Singleton kodlanırken hem de ona erişmek için kod yazılırken, program değişkenlerinizle ne yapmaya çalıştığınız konusunda kendinize yüklenen birkaç kısıtlamayı izlemeden yapabileceğiniz iş yükü ek iş yükü getirir.

Yani, nihai bir sonuç olarak: singletonunuz gayet iyi. Singleton'u hiç kullanmamak çoğu zaman da iyidir.


2

Yorumunuz doğru. Singletonların yeri var ama aşırı kullanılıyor. Genellikle, statik üye işlevlerine erişmek yeterlidir (özellikle inşaat süresini herhangi bir şekilde kontrol etmeniz gerekmediğinde). Daha iyisi, bir ad alanına bazı ücretsiz işlevler ve değişkenler koyabilirsiniz.


2

Programlama sırasında "doğru" ve "yanlış" yoktur; "iyi uygulama" ve "kötü uygulama" vardır.

Tektonlar genellikle daha sonra tekrar kullanılmak üzere bir sınıf olarak oluşturulur. Programcının gece yarısı sarhoş kodlama yaparken yanlışlıkla iki örneği somutlaştırmayacak şekilde yaratılması gerekir.

Eğer basit bir küçük sınıf varsa olmamalıdır defadan fazla başlatılamaz, sen yok lüzum bir tekil yapmak. Sadece bir güvenlik ağı yaparsan.

küresel nesnelere sahip olmak her zaman kötü bir uygulama değildir . Küresel olarak / her yerde / her zaman kullanacağınızı biliyorsanız, birkaç istisnadan biri olabilir. Ancak, küreseller genellikle kötü uygulama olarak kabul edilen şekilde "kötü uygulama" gotoolarak kabul edilir.


2

Buna hiç bir şey görmüyorum. Sınıfı, bağlantı dizesinin kurucuya bir parametre olarak alınacağı ve PDO nesnelerinin bir listesini (her bir benzersiz bağlantı dizesi için bir tane) koruyacak şekilde uyguladıysanız, belki bazı faydalar olacaktır, ancak bu örnek anlamsız bir alıştırma gibi görünüyor.


1

Görebildiğim kadarıyla hiçbir şeyi kaçırmıyorsun. Örnek oldukça kusurlu. Singleton sınıfının statik olmayan bazı örnek değişkenleri olsaydı bu fark yaratacaktır.

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.