Apakah ada kasus penggunaan untuk lajang dengan akses database di PHP?


138

Saya mengakses database MySQL saya melalui PDO. Saya mengatur akses ke database, dan upaya pertama saya adalah menggunakan yang berikut:

Hal pertama yang saya pikirkan adalah global:

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

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

Ini dianggap praktik buruk. Setelah sedikit pencarian, saya berakhir dengan pola Singleton , yang mana

"Berlaku untuk situasi di mana perlu ada satu instance kelas."

Menurut contoh dalam manual, kita harus melakukan ini:

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();

Mengapa saya perlu kelas yang relatif besar ketika saya bisa melakukan ini?

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();

Yang terakhir ini bekerja dengan sempurna dan saya tidak perlu khawatir $dblagi.

Bagaimana saya bisa membuat kelas singleton yang lebih kecil, atau adakah case-use untuk lajang yang saya lewatkan di PHP?


Ada banyak sumber daya dan diskusi dalam pertanyaan terkait ini: 'Apa yang sangat buruk tentang lajang?'
FruitBreak

Jawaban:


80

Oke, saya bertanya-tanya tentang hal itu untuk sementara waktu ketika saya pertama kali memulai karir saya. Diimplementasikan dengan cara yang berbeda dan muncul dengan dua alasan untuk memilih untuk tidak menggunakan kelas statis, tetapi mereka cukup besar.

Salah satunya adalah Anda akan menemukan sesuatu yang sangat sering Anda yakin benar-benar tidak akan pernah memiliki lebih dari satu contoh, Anda akhirnya memiliki satu detik. Anda mungkin berakhir dengan monitor kedua, database kedua, server kedua - apa pun.

Ketika ini terjadi, jika Anda telah menggunakan kelas statis Anda berada dalam refactor yang jauh lebih buruk daripada jika Anda menggunakan singleton. Singleton adalah pola yang rapuh dalam dirinya sendiri, tetapi mengkonversi dengan mudah menjadi pola pabrik yang cerdas - bahkan dapat dikonversi untuk menggunakan injeksi ketergantungan tanpa terlalu banyak kesulitan. Misalnya, jika singleton Anda diperoleh melalui getInstance (), Anda dapat dengan mudah mengubahnya menjadi getInstance (databaseName) dan memungkinkan beberapa basis data - tidak ada perubahan kode lainnya.

Masalah kedua adalah pengujian (Dan jujur, ini sama dengan masalah pertama). Terkadang Anda ingin mengganti database Anda dengan database tiruan. Akibatnya ini adalah contoh kedua dari objek database. Ini jauh lebih sulit untuk dilakukan dengan kelas statis daripada dengan singleton, Anda hanya perlu mengejek metode getInstance (), tidak setiap metode tunggal di kelas statis (yang dalam beberapa bahasa bisa sangat sulit).

Ini benar-benar berasal dari kebiasaan - dan ketika orang mengatakan "global" itu buruk, mereka punya alasan yang sangat bagus untuk mengatakannya, tetapi itu mungkin tidak selalu jelas sampai Anda sendiri yang berhasil menyelesaikan masalahnya.

Hal terbaik yang dapat Anda lakukan adalah bertanya (seperti yang Anda lakukan) kemudian membuat pilihan dan mengamati akibat dari keputusan Anda. Memiliki pengetahuan untuk menafsirkan evolusi kode Anda dari waktu ke waktu jauh lebih penting daripada melakukannya dengan benar.


15
Anda mengatakan bahwa lajang menurun dengan baik ke DI, tetapi bukankah contoh Anda getInstance(databaseName)hanya menyebarkan referensi ke repositori global contoh di seluruh kode Anda? Kode yang akan memanggil getInstanceharus memiliki instance (s) yang disuntikkan ke dalamnya oleh kode klien, dan karenanya tidak perlu menelepon getInstanceterlebih dahulu.
Will Vousden

1
@ Will Vousden Benar, ini semacam stop-gap. Ini tidak benar-benar DI, tetapi bisa sangat dekat. Misalnya, bagaimana jika itu getInstance (database yang didukung) dan instance yang dikembalikan dihitung berdasarkan basis data mana yang dilewati? Intinya adalah untuk menghindari menakut-nakuti orang dengan kerangka DI sampai mereka siap untuk itu.
Bill K

320

Lajang memiliki sangat sedikit - jika tidak untuk mengatakan tidak - gunakan dalam PHP.

Dalam bahasa tempat objek hidup dalam memori bersama, Singletons dapat digunakan untuk menjaga penggunaan memori rendah. Alih-alih membuat dua objek, Anda mereferensikan instance yang ada dari memori aplikasi yang dibagikan secara global. Di PHP tidak ada memori aplikasi seperti itu. Seorang Singleton yang dibuat dalam satu Permintaan hidup sesuai permintaan itu. Singleton yang dibuat dalam Permintaan lain yang dilakukan pada saat yang sama masih merupakan contoh yang sama sekali berbeda. Dengan demikian, salah satu dari dua tujuan utama Singleton tidak berlaku di sini.

Selain itu, banyak objek yang secara konseptual dapat ada hanya sekali dalam aplikasi Anda tidak perlu memerlukan mekanisme bahasa untuk menegakkan ini. Jika Anda hanya membutuhkan satu instance, maka jangan instantiate yang lain . Hanya ketika Anda mungkin tidak memiliki instance lain, misalnya ketika anak kucing mati ketika Anda membuat instance kedua, Anda mungkin memiliki Use Case yang valid untuk Singleton.

Tujuan lainnya adalah memiliki jalur akses global ke instance dalam Permintaan yang sama. Walaupun ini mungkin terdengar diinginkan, itu benar-benar tidak, karena ia menciptakan sambungan ke ruang lingkup global (seperti global dan statika). Ini membuat Unit-Testing lebih sulit dan aplikasi Anda secara umum kurang terpelihara. Ada cara untuk mengurangi ini, tetapi secara umum, jika Anda perlu memiliki contoh yang sama di banyak kelas, gunakan Injeksi Ketergantungan .

Lihat slide saya untuk lajang di PHP - Mengapa buruk dan bagaimana Anda bisa menghilangkannya dari aplikasi Anda untuk informasi tambahan.

Bahkan Erich Gamma , salah satu penemu pola Singleton, meragukan pola ini saat ini:

"Aku mendukung menjatuhkan Singleton. Penggunaannya hampir selalu berbau desain"

Bacaan lebih lanjut

Jika, setelah hal di atas, Anda masih perlu bantuan untuk memutuskan:

Diagram Keputusan Singleton


1
@ Hamilton ya. Dan bahkan jika itu mungkin untuk mempertahankan objek antara permintaan, Lajang masih melanggar beberapa prinsip SOLID dan memperkenalkan Negara Global.
Gordon

4
Maaf untuk menentang arus, tetapi DI sebenarnya bukan solusi untuk masalah yang digunakan Singleton, kecuali Anda puas dengan memiliki kelas dengan 42 parameter ctor (atau 42 setFoo () dan panggilan setBar () yang diperlukan untuk membuatnya kerja). Ya, beberapa aplikasi, sayangnya, harus digabungkan dan bergantung pada banyak hal eksternal. PHP adalah bahasa lem, dan kadang-kadang ada banyak hal untuk disatukan.
StasM

14
@StasM jika Anda memiliki 42 partor ctor atau membutuhkan banyak seter yang Anda lakukan salah Tonton Pembicaraan Kode Bersih, silakan. Maaf, jika saya tidak bisa repot-repot untuk menjelaskan ini lain kali. Silakan bertanya di chatroom PHP untuk info lebih lanjut.
Gordon

@Gordon Di mana ruang obrolan php?
user658182

21

Siapa yang butuh lajang di PHP?

Perhatikan bahwa hampir semua keberatan terhadap lajang berasal dari sudut pandang teknis - tetapi mereka juga sangat terbatas dalam ruang lingkup mereka. Khusus untuk PHP. Pertama, saya akan membuat daftar beberapa alasan untuk menggunakan lajang, dan kemudian saya akan menganalisis keberatan untuk penggunaan lajang. Pertama, orang yang membutuhkannya:

- Orang-orang yang mengkode kerangka kerja / basis kode besar, yang akan digunakan di banyak lingkungan yang berbeda, harus bekerja dengan kerangka kerja / kerangka kerja yang berbeda yang sudah ada sebelumnya, dengan kebutuhan untuk mengimplementasikan berbagai permintaan yang berbeda, berubah, bahkan aneh dari klien / bos. / pimpinan manajemen / unit lakukan.

Lihat, pola singleton inklusif. Ketika selesai, sebuah kelas tunggal kaku di semua kode tempat Anda memasukkannya, dan ia bertindak persis seperti cara Anda membuat metode dan variabelnya. Dan itu selalu objek yang sama dalam permintaan yang diberikan. Karena tidak dapat dibuat dua kali menjadi dua objek yang berbeda, Anda tahu apa objek singleton pada titik tertentu dalam kode - bahkan jika singleton dimasukkan ke dua, tiga kode basis spaghetti yang berbeda, lama, bahkan berbeda. Oleh karena itu, membuatnya lebih mudah dalam hal tujuan pengembangan - bahkan jika ada banyak orang yang bekerja di proyek itu, ketika Anda melihat singleton diinisialisasi dalam satu titik dalam basis kode apa pun yang diberikan, Anda tahu apa itu, apa yang dilakukannya, bagaimana tidak, dan negara itu di. Jika itu adalah kelas tradisional, Anda harus melacak di mana objek itu pertama kali dibuat, metode apa yang digunakan di dalamnya sampai saat itu dalam kode, dan keadaan khusus. Tapi, letakkan singleton di sana, dan jika Anda menjatuhkan metode debug dan informasi yang tepat dan melacak ke singleton saat mengkodekannya, Anda tahu persis apa itu. Jadi karena itu, membuatnya lebih mudah bagi orang-orang yang harus bekerja dengan basis kode yang berbeda, dengan perlunya mengintegrasikan kode yang dilakukan sebelumnya dengan filosofi yang berbeda, atau dilakukan oleh orang-orang yang Anda tidak memiliki kontak dengan. (Yaitu, vendor-proyek-perusahaan-apa pun yang ada, tidak ada dukungan apa-apa). itu membuatnya lebih mudah bagi orang-orang yang harus bekerja dengan basis kode yang berbeda, dengan perlunya mengintegrasikan kode yang dilakukan sebelumnya dengan filosofi yang berbeda, atau dilakukan oleh orang-orang yang Anda tidak memiliki kontak dengan. (Yaitu, vendor-proyek-perusahaan-apa pun yang ada, tidak ada dukungan apa-apa). itu membuatnya lebih mudah bagi orang-orang yang harus bekerja dengan basis kode yang berbeda, dengan perlunya mengintegrasikan kode yang dilakukan sebelumnya dengan filosofi yang berbeda, atau dilakukan oleh orang-orang yang Anda tidak memiliki kontak dengan. (Yaitu, vendor-proyek-perusahaan-apa pun yang ada, tidak ada dukungan apa-apa).

- Orang yang perlu bekerja dengan API , layanan, dan situs web pihak ketiga .

Jika Anda melihat lebih dekat, ini tidak jauh berbeda dari kasus sebelumnya - API pihak ketiga, layanan, situs web, seperti basis kode eksternal yang terisolasi di mana Anda tidak memiliki kendali. Segalanya bisa terjadi. Jadi, dengan sesi tunggal / kelas pengguna, Anda dapat mengelola SETIAP jenis sesi / otorisasi implementasi dari penyedia pihak ketiga seperti OpenID , Facebook , Twitter dan banyak lagi - dan Anda dapat melakukan SEMUA ini pada saat yang sama dari objek singleton SAMA. - yang mudah diakses, dalam kondisi diketahui pada titik tertentu dalam kode apa pun yang Anda tancapkan. Anda bahkan dapat membuat beberapa sesi ke beberapa API / layanan pihak ketiga yang berbeda untuk pengguna SAMA di situs web / aplikasi Anda sendiri, dan melakukan apa pun yang ingin Anda lakukan dengannya.

Tentu saja, semua ini juga dapat menjadi nada dengan metode tradisional dengan menggunakan kelas dan objek normal - tangkap di sini adalah, singleton lebih rapi, lebih rapi dan karena itu lebih mudah dikelola / diuji dibandingkan dengan penggunaan kelas / objek tradisional dalam situasi seperti itu.

- Orang yang perlu melakukan pengembangan cepat

Perilaku lajang seperti global memudahkan untuk membangun segala jenis kode dengan kerangka kerja yang memiliki kumpulan lajang untuk dibangun, karena begitu Anda membangun kelas-kelas lajang Anda dengan baik, metode yang mapan, matang, dan kumpulan akan mudah tersedia dan dapat digunakan di mana saja, kapan saja, secara konsisten. Butuh beberapa waktu untuk mematangkan kelas Anda, tetapi setelah itu, mereka sangat solid dan konsisten, dan berguna. Anda dapat memiliki banyak metode dalam singleton melakukan apa pun yang Anda inginkan, dan, meskipun ini dapat meningkatkan jejak memori objek, itu membawa lebih banyak penghematan waktu yang dibutuhkan untuk pengembangan cepat - metode yang tidak Anda gunakan dalam satu contoh yang diberikan suatu aplikasi dapat digunakan dalam aplikasi terintegrasi lainnya, dan Anda bisa menampar fitur baru yang diminta klien / bos / manajer proyek hanya dengan beberapa modifikasi.

Anda mendapatkan idenya. Sekarang mari kita beralih ke keberatan terhadap lajang dan perang suci yang tidak suci terhadap sesuatu yang berguna :

- Keberatan utama adalah bahwa hal itu membuat pengujian lebih sulit.

Dan sungguh, memang sampai batas tertentu, bahkan jika itu dapat dengan mudah dikurangi dengan mengambil tindakan pencegahan yang tepat dan coding rutinitas debugging ke lajang Anda DENGAN kesadaran bahwa Anda akan men-debug tunggal. Tapi lihat, ini tidak terlalu berbeda dengan filosofi / metode / pola pengkodean APAPUN yang ada di luar sana - hanya saja, lajang relatif baru dan tidak tersebar luas, sehingga metode pengujian saat ini berakhir dengan perbandingan yang tidak sesuai dengan mereka. Tapi itu tidak berbeda dalam aspek bahasa pemrograman - gaya yang berbeda memerlukan pendekatan yang berbeda.

Satu titik keberatan ini jatuh datar dalam hal itu, ia mengabaikan fakta bahwa alasan aplikasi dikembangkan bukan untuk 'pengujian', dan pengujian bukan satu-satunya fase / proses yang masuk ke dalam pengembangan aplikasi. Aplikasi dikembangkan untuk penggunaan produksi. Dan seperti yang saya jelaskan di bagian 'siapa yang butuh lajang', lajang dapat memotong banyak dari kerumitan harus membuat kode bekerja DENGAN dan DI DALAM banyak basis kode / aplikasi / layanan pihak ketiga yang berbeda. Waktu yang mungkin hilang dalam pengujian, adalah waktu yang diperoleh dalam pengembangan dan penyebaran. Ini sangat berguna di era otentikasi / aplikasi / integrasi pihak ketiga ini - Facebook, Twitter, OpenID, banyak lagi dan siapa yang tahu apa yang akan terjadi selanjutnya.

Meskipun dapat dimengerti - programmer bekerja dalam keadaan yang sangat berbeda tergantung pada karir mereka. Dan untuk orang-orang yang bekerja di perusahaan yang relatif besar dengan departemen yang jelas cenderung berbeda, perangkat lunak / aplikasi yang ditentukan dengan cara yang nyaman dan tanpa malapetaka yang akan datang pemotongan anggaran / PHK dan kebutuhan menyertainya untuk melakukan BANYAK hal dengan banyak hal yang berbeda dalam fashion murah / cepat / dapat diandalkan, lajang mungkin tidak begitu diperlukan. Dan itu bahkan dapat mengganggu / menghalangi apa yang mereka miliki.

Tetapi bagi mereka yang perlu bekerja di parit kotor pengembangan 'gesit', harus menerapkan banyak permintaan berbeda (kadang-kadang tidak masuk akal) dari klien / manajer / proyek mereka, lajang adalah anugerah yang menyelamatkan karena alasan yang dijelaskan sebelumnya.

- Keberatan lainnya adalah jejak memorinya lebih tinggi

Karena singleton baru akan ada untuk setiap permintaan dari setiap klien, MUNGKIN ini menjadi keberatan untuk PHP. Dengan singleton yang dibangun dan digunakan dengan buruk, jejak memori suatu aplikasi bisa lebih tinggi jika banyak pengguna dilayani oleh aplikasi pada titik tertentu.

Padahal, ini berlaku untuk pendekatan APAPUN yang dapat Anda ambil saat melakukan pengkodean. Pertanyaan yang harus ditanyakan adalah, apakah metode, data yang disimpan dan diproses oleh lajang ini tidak perlu? Karena, jika mereka diperlukan di banyak permintaan aplikasi yang didapat, maka bahkan jika Anda tidak menggunakan lajang, metode dan data tersebut AKAN hadir dalam aplikasi Anda dalam beberapa bentuk atau lainnya melalui kode. Jadi, itu semua menjadi pertanyaan tentang berapa banyak memori yang akan Anda simpan, ketika Anda menginisialisasi objek kelas tradisional 1/3 ke dalam pemrosesan kode, dan menghancurkannya 3/4 ke dalamnya.

Lihat, ketika diajukan seperti ini, pertanyaannya menjadi sangat tidak relevan - seharusnya tidak ada metode yang tidak perlu, data disimpan dalam objek dalam kode Anda ANYWAY - terlepas dari Anda menggunakan lajang atau tidak. Jadi, keberatan terhadap lajang ini menjadi sangat lucu dalam hal itu, ASUMSI bahwa akan ada metode yang tidak perlu, data dalam objek yang dibuat dari kelas yang Anda gunakan.

- Beberapa keberatan yang tidak valid seperti 'membuat mempertahankan beberapa koneksi basis data menjadi tidak mungkin / sulit'

Saya bahkan tidak dapat mulai memahami keberatan ini, ketika semua orang perlu memelihara beberapa koneksi basis data, banyak pilihan basis data, beberapa permintaan basis data, beberapa set hasil dalam singleton yang diberikan hanya menjaga mereka dalam variabel / array dalam singleton selama mereka dibutuhkan. Ini bisa sesederhana menjaga mereka dalam array, meskipun Anda dapat menemukan metode apa pun yang ingin Anda gunakan untuk melakukan itu. Tapi mari kita periksa kasus paling sederhana, penggunaan variabel dan array dalam singleton yang diberikan:

Bayangkan di bawah ini ada di dalam database tunggal yang diberikan:

$ this -> koneksi = array (); (sintaks yang salah, saya hanya mengetiknya seperti ini untuk memberi Anda gambaran - deklarasi variabel yang tepat adalah public $ koneksi = array (); dan penggunaannya adalah $ this-> koneksi ['koneksikey'] secara alami)

Anda dapat mengatur, dan menjaga beberapa koneksi pada waktu tertentu dalam array dengan cara ini. Dan hal yang sama berlaku untuk kueri, set hasil, dan sebagainya.

$ this -> query (QUERYSTRING, 'queryname', $ this-> koneksi ['particulrconnection']);

Yang hanya bisa melakukan kueri ke database yang dipilih dengan koneksi yang dipilih, dan simpan saja di

$ this -> hasil

array dengan kunci 'queryname'. Tentu saja, Anda perlu memiliki kode metode kueri Anda untuk ini - yang sepele untuk dilakukan.

Ini memungkinkan Anda untuk mempertahankan jumlah koneksi database dan set hasil yang hampir tak terbatas (sebanyak batas sumber daya tentu saja) sebanyak yang Anda perlukan. Dan mereka tersedia untuk SETIAP bagian kode dalam titik tertentu dalam basis kode apa pun yang diberikan ke mana kelas tunggal ini dipakai.

TENTU SAJA, Anda tentu perlu membebaskan set hasil, dan koneksi bila tidak diperlukan - tetapi itu tidak perlu dikatakan, dan itu tidak spesifik untuk lajang atau metode pengkodean / gaya / konsep pengkodean lainnya.

Pada titik ini, Anda dapat melihat bagaimana Anda dapat mempertahankan beberapa koneksi / status ke aplikasi atau layanan pihak ketiga dalam satu singleton. Tidak terlalu berbeda.

Singkatnya, pada akhirnya, pola singleton hanyalah metode / gaya / filosofi lain untuk diprogram, dan mereka sama bermanfaatnya dengan yang lainnya ketika digunakan di tempat yang benar, dengan cara yang benar. Yang tidak berbeda dari apa pun.

Anda akan melihat bahwa di sebagian besar artikel di mana lajang dihancurkan, Anda juga akan melihat referensi 'global' menjadi 'jahat'.

Mari kita hadapi itu - Apa pun yang tidak digunakan dengan benar, dilecehkan, disalahgunakan, IS jahat. Itu tidak terbatas pada bahasa apa pun, konsep pengkodean apa pun, metode apa pun. Setiap kali Anda melihat seseorang mengeluarkan pernyataan selimut seperti 'X itu jahat', larilah dari artikel itu. Peluangnya sangat tinggi sehingga merupakan produk dari sudut pandang terbatas - bahkan jika sudut pandang tersebut adalah hasil dari pengalaman bertahun-tahun dalam sesuatu yang khusus - yang pada akhirnya berakhir sebagai hasil dari bekerja terlalu banyak dalam gaya / metode tertentu - konservatisme intelektual tipikal.

Contoh tak berujung dapat diberikan untuk itu, mulai dari 'global adalah kejahatan' hingga 'iframe adalah jahat'. Kembali sekitar 10 tahun yang lalu, bahkan mengusulkan penggunaan iframe dalam aplikasi apa pun adalah bid'ah. Kemudian datang Facebook, iframe di mana-mana, dan lihat apa yang terjadi - iframe tidak lagi jahat.

Masih ada orang-orang yang dengan keras kepala bersikeras bahwa mereka 'jahat' - dan kadang-kadang juga untuk alasan yang baik - tetapi, seperti yang Anda lihat, ada kebutuhan, iframes memenuhi kebutuhan itu dan bekerja dengan baik, dan karena itu seluruh dunia terus bergerak.

Aset utama seorang programmer / programmer / insinyur perangkat lunak adalah pikiran yang bebas, terbuka, dan fleksibel.


2
-1. Walaupun saya setuju bahwa memiliki pikiran yang terbuka dan fleksibel adalah harus memiliki aset untuk pengembang mana pun, itu tidak membebaskan Singleton dari menjadi Antipattern. Jawaban di atas mengandung begitu banyak pernyataan yang tidak akurat dan kesimpulan yang salah tentang sifat dan efek Singleton yang tidak bisa saya hilangkan begitu saja.
Gordon

-1. Saya harus mengalami kerangka kerja dengan banyak lajang tangan pertama dan pengujian otomatis tidak mungkin. Saya harus menguji semuanya secara manual melalui coba-coba di browser. Beberapa kesalahan mungkin dapat dicegah dengan ulasan kode (kesalahan ejaan, sintaksis) tetapi kesalahan fungsional sering disembunyikan. Pengujian ini membutuhkan lebih banyak waktu daripada pengujian unit. Dengan tes unit saya bisa mengatakan: Kelas ini bekerja secara terpisah, kesalahannya harus di tempat lain. Tanpa debugging itu membosankan.
Jim Martens

Kerangka kerja harus dibangun di logging dan pelacakan kesalahan. Juga, kelas yang bekerja dengan baik dalam isolasi, juga akan bekerja dengan baik dalam bentuk tunggal ketika dimasukkan ke dalam aplikasi yang lebih luas. Yang berarti bahwa dalam hal itu apa yang melanggar akan menjadi kelas atau fungsi lain yang berinteraksi dengan singleton itu. Ini tidak berbeda dengan pelacakan bug biasa di dalam aplikasi besar. Yang itu sendiri cukup sulit tanpa aplikasi memiliki pencatatan yang tepat.
unity100

Tidak akurat Banyak singletones pasti JAHAT, karena ia menciptakan Testing-NERAKA. :-) Namun, satu singletone per aplikasi bisa bagus. Misalnya: sebagai fitur pencatatan log terpadu - untuk diterapkan di semua aplikasi (termasuk beberapa kode lama).
Filip OvertoneSinger Rydlo

"Waktu yang mungkin hilang dalam pengujian ..." Ini adalah praktik dan cara berpikir yang benar-benar buruk. Semua aplikasi warisan di luar sana yang dikembangkan dengan mempertimbangkan hal ini dan menjadi tidak mungkin untuk mempertahankannya sehingga harus ditulis ulang. Jika tidak ada tes, waktu akan hilang ketika fitur baru dikembangkan dan merusak sesuatu di bagian lain dari sistem. Waktu hilang saat debugging, waktu hilang oleh pengguna yang dapat menggunakan fitur itu dengan benar, kepercayaan pada aplikasi hilang dll.
bogdancep

15

Lajang dianggap oleh banyak orang sebagai anti-pola karena mereka benar-benar hanya memuliakan variabel global. Dalam prakteknya ada relatif sedikit skenario di mana itu diperlukan untuk kelas untuk memiliki hanya satu contoh; biasanya hanya satu contoh saja sudah cukup , dalam hal mengimplementasikannya sebagai singleton sama sekali tidak perlu.

Untuk menjawab pertanyaan, Anda benar bahwa lajang terlalu banyak di sini. Variabel atau fungsi sederhana akan dilakukan. Namun, pendekatan yang lebih baik (lebih kuat) akan menggunakan injeksi ketergantungan untuk menghilangkan kebutuhan variabel global secara keseluruhan.


Tapi Singletons dapat terdegradasi dengan sangat lancar menjadi DI, kelas statis tidak bisa, yang merupakan masalah nyata dengan kelas statis.
Bill K

@ Bill: Sangat benar, tapi kemudian itu sebabnya saya menganjurkan pendekatan DI untuk memulai, daripada fungsi longgar atau metode statis :)
Will Vousden

Dalam beberapa bahasa (seperti Java) kelas statis (atau metode statis kelas) tidak dapat diperpanjang. Jadi, Anda menciptakan masalah potensial (atau paling baik, lebih banyak pekerjaan) untuk pengembang masa depan. Jadi beberapa menyarankan bahwa metode statis harus dihindari secara umum kecuali Anda memiliki kebutuhan khusus untuk mereka.
Marvo

8

Dalam contoh Anda, Anda sedang berhadapan dengan sepotong informasi yang tampaknya tidak berubah. Untuk contoh ini, seorang Singleton akan menjadi terlalu banyak dan hanya menggunakan fungsi statis di kelas akan baik-baik saja.

Lebih banyak pemikiran: Anda mungkin mengalami kasus penerapan pola demi pola dan nyali Anda memberi tahu Anda "tidak, Anda tidak harus" karena alasan Anda mengeja.

TAPI: Kami tidak tahu ukuran dan ruang lingkup proyek Anda. Jika ini adalah kode sederhana, mungkin dibuang, yang sepertinya tidak perlu diubah maka ya, silakan dan gunakan anggota statis. Tetapi, jika Anda berpikir bahwa proyek Anda mungkin perlu skala atau dipersiapkan untuk pemeliharaan kode di jalan maka, ya, Anda mungkin ingin menggunakan pola Singleton.


1
Wow, salah besar. Inti dari perbedaan (jawaban atas pertanyaan) adalah seberapa sulit nantinya memperbaiki kode Anda untuk menambahkan contoh kedua. Jauh lebih sulit untuk melakukannya jika Anda menggunakan metode statis. Ini seperti mengatakan "Global baik-baik saja dalam kondisi terbatas Anda" ketika seluruh masalah dengan Globals adalah bahwa kondisinya berubah.
Bill K

@ Bill K: Saya setuju dengan Anda dan saya akan menggunakan singleton jika ada kerumitan sama sekali. Tetapi saya mencoba menjawab pertanyaan dari sudut pandang OP dan berpikir, ya, saya kira itu berlebihan dalam kasus yang sangat terbatas ini. Tentu saja saya mengabaikan masalah arsitektur atau skalabilitas dan banyak pertimbangan lainnya. Haruskah saya memasukkan itu sebagai peringatan dalam jawaban saya juga dengan penjelasan tentang mengapa seseorang harus selalu menggunakan singleton ... yang tentu saja akan menyebabkan suara turun dari orang lain?
Paul Sasik

5

Pertama, saya hanya ingin mengatakan bahwa saya tidak menemukan banyak kegunaan untuk pola Singleton. Mengapa seseorang ingin menyimpan satu objek di seluruh aplikasi? Khusus untuk basis data, bagaimana jika saya ingin terhubung ke server basis data lain? Saya harus memutuskan dan menghubungkan kembali setiap kali ...? Bagaimanapun...

Ada beberapa kelemahan untuk menggunakan global dalam suatu aplikasi (yang dilakukan oleh pola Singleton secara tradisional):

  • Sulit untuk uji unit
  • Masalah injeksi ketergantungan
  • Dapat membuat masalah penguncian (aplikasi multi-utas)

Gunakan kelas statis alih-alih sebuah instance singleton menyediakan beberapa kelemahan yang sama juga, karena masalah terbesar singleton adalah getInstancemetode statis .

Anda dapat membatasi jumlah instance kelas yang dapat dimiliki tanpa menggunakan getInstancemetode tradisional :

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

Ini akan membantu pada poin pertama yang disebutkan di atas: pengujian unit dan injeksi ketergantungan; sambil tetap memastikan satu instance kelas ada di aplikasi Anda. Anda bisa, misalnya, hanya meneruskan objek yang dihasilkan ke model Anda (pola MVC) untuk digunakan.


5

Pertimbangkan secara sederhana bagaimana solusi Anda berbeda dari yang disajikan dalam dokumen PHP. Faktanya, hanya ada satu perbedaan "kecil": solusi Anda memberikan penelepon pada pengambil dengan sebuah PDOinstance, sedangkan yang dalam docs menyediakan penelepon Database::singletondengan Databaseinstance (mereka kemudian menggunakan getter untuk mendapatkanPDO contoh).

Jadi kesimpulan apa yang kita capai?

  • Dalam kode dokumentasi, penelepon mendapat Databasecontoh. The Databasekelas dapat mengekspos (pada kenyataannya, itu harus mengekspos jika Anda 'kembali akan semua masalah ini) antarmuka yang lebih kaya atau tingkat lebih tinggi dari PDOobjek itu membungkus.
  • Jika Anda mengubah implementasi Anda untuk mengembalikan tipe (lebih kaya) selain PDO , maka kedua implementasi itu setara. Tidak ada untung yang didapat dari mengikuti implementasi manual.

Di sisi praktis, Singleton adalah pola yang cukup kontroversial. Ini terutama karena:

  • Terlalu sering digunakan. Pemrogram pemula grok Singleton jauh lebih mudah daripada mereka grok pola lainnya. Mereka kemudian melanjutkan untuk menerapkan pengetahuan baru mereka di mana-mana, bahkan jika masalah yang ada dapat diselesaikan lebih baik tanpa Singleton (ketika Anda memegang palu, semuanya terlihat seperti paku).
  • Bergantung pada bahasa pemrogramannya, mengimplementasikan Singleton dengan cara yang kedap udara dan tidak bocor dapat menjadi tugas yang sangat besar (terutama jika kita memiliki skenario tingkat lanjut: singleton tergantung pada singleton lain, lajang yang dapat dihancurkan dan diciptakan kembali, dll. ). Coba saja cari implementasi Singleton "definitif" di C ++, saya berani Anda (saya memiliki desain C ++ Desain inovatif Andrei Alexandrescu, yang mendokumentasikan banyak kekacauan).
  • Ini membebankan beban kerja tambahan baik ketika mengkodekan Singleton dan ketika menulis kode untuk mengaksesnya, beban kerja yang dapat Anda lakukan tanpa mengikuti beberapa batasan yang dipaksakan sendiri pada apa yang Anda coba lakukan dengan variabel program Anda.

Jadi, sebagai kesimpulan akhir: singleton Anda baik-baik saja. Tidak menggunakan Singleton sama sekali tidak masalah sebagian besar waktu juga.


2

Penafsiran Anda benar. Lajang memiliki tempat mereka tetapi terlalu sering digunakan. Seringkali, mengakses fungsi anggota statis sudah cukup (terutama, ketika Anda tidak perlu mengontrol waktu konstruksi dengan cara apa pun). Lebih baik, Anda bisa meletakkan beberapa fungsi dan variabel gratis di namespace.


2

Saat pemrograman tidak ada "benar" dan "salah"; ada "praktik yang baik" dan "praktik yang buruk".

Lajang umumnya dibuat sebagai kelas untuk digunakan kembali nanti. Mereka perlu dibuat sedemikian rupa sehingga programmer tidak sengaja membuat instance dua saat sambil mabuk coding di tengah malam.

Jika Anda memiliki kelas kecil sederhana yang tidak boleh dipakai lebih dari satu kali, Anda tidak perlu menjadikannya singleton. Itu hanya jaring pengaman jika Anda melakukannya.

itu tidak selalu praktik buruk untuk memiliki objek global. Jika Anda tahu bahwa Anda akan menggunakannya secara global / di mana saja / sepanjang waktu, itu mungkin salah satu dari sedikit pengecualian. Namun, global umumnya dianggap "praktik buruk" dengan cara yang sama yang gotodianggap praktik buruk.


2

Saya tidak melihat ada gunanya sama sekali. Jika Anda menerapkan kelas sedemikian rupa sehingga string koneksi diambil sebagai parameter ke konstruktor dan memelihara daftar objek PDO (satu untuk setiap string koneksi unik) maka mungkin akan ada beberapa manfaat, tetapi implementasi singleton di contoh ini sepertinya latihan yang sia-sia.


1

Anda tidak melewatkan apa pun, sejauh yang saya bisa lihat. Contohnya cukup cacat. Itu akan membuat perbedaan, jika kelas singleton memiliki beberapa variabel instance non-statis.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.