Jawaban di bawah ini salah, tetapi saya akan menyimpannya agar orang lain dapat belajar darinya (lihat di bawah)
Di ExampleA
, Anda dapat menggunakan Config
contoh yang sama di beberapa kelas. Namun, jika harus ada hanya satu Config
instance dalam seluruh aplikasi, pertimbangkan menerapkan pola Singleton pada Config
untuk menghindari memiliki beberapa instance Config
. Dan jika Anda Config
seorang Singleton, Anda bisa melakukan yang berikut:
class ExampleA
{
private $config;
public function __construct()
{
$this->config = Config->getInstance();
}
}
$exampleA = new ExampleA();
Di ExampleB
sisi lain, Anda akan selalu mendapatkan instance terpisah Config
untuk setiap instance ExampleB
.
Versi mana yang harus Anda terapkan benar-benar tergantung pada bagaimana aplikasi akan menangani instance dari Config
:
- jika setiap instance
ExampleX
harus memiliki instance terpisah Config
, ikuti ExampleB
;
- jika setiap instance
ExampleX
akan membagikan satu (dan hanya satu) instance dari Config
, gunakan ExampleA with Config Singleton
;
- Jika contoh
ExampleX
dapat menggunakan contoh berbeda Config
, tetap dengan ExampleA
.
Mengapa Config
menjadi Singleton salah:
Saya harus mengakui bahwa saya baru belajar tentang pola Singleton kemarin (membaca buku Kepala Pertama pola desain). Secara naif saya pergi dan menerapkannya untuk contoh ini, tetapi seperti yang telah ditunjukkan banyak orang, satu cara yang lain (beberapa lebih samar dan hanya mengatakan "Anda salah!"), Ini bukan ide yang baik. Jadi, untuk mencegah orang lain melakukan kesalahan yang sama seperti yang baru saja saya lakukan, berikut ini ringkasan mengapa pola Singleton bisa berbahaya (berdasarkan komentar dan apa yang saya temukan di Google):
Jika ExampleA
mengambil referensi sendiri ke Config
instance, kelas akan digabungkan secara ketat. Tidak akan ada cara ExampleA
untuk menggunakan versi yang berbeda dari Config
(misalnya beberapa subclass). Ini mengerikan jika Anda ingin menguji ExampleA
menggunakan contoh mock-up Config
karena tidak ada cara untuk menyediakannya ExampleA
.
Premis akan ada satu, dan hanya satu, contoh dari Config
mungkin berlaku sekarang , tetapi Anda tidak selalu dapat memastikan bahwa hal yang sama akan berlaku di masa depan . Jika pada suatu saat nanti ternyata beberapa contoh Config
akan diinginkan, tidak ada cara untuk mencapai ini tanpa menulis ulang kode.
Meskipun instance satu-dan-hanya-satu Config
mungkin benar untuk selamanya, itu bisa terjadi bahwa Anda ingin dapat menggunakan beberapa subclass dari Config
(sementara masih hanya memiliki satu instance). Tetapi, karena kode secara langsung mendapatkan instance via getInstance()
dari Config
, yang merupakan static
metode, tidak ada cara untuk mendapatkan subclass. Sekali lagi, kode harus ditulis ulang.
Fakta bahwa ExampleA
penggunaan Config
akan disembunyikan, setidaknya ketika hanya melihat API ExampleA
. Ini mungkin atau mungkin bukan hal yang buruk, tetapi secara pribadi saya merasa ini terasa tidak menguntungkan; misalnya, ketika mempertahankan, tidak ada cara sederhana untuk mengetahui kelas mana yang akan terpengaruh oleh perubahan Config
tanpa melihat ke dalam implementasi setiap kelas lainnya.
Bahkan jika fakta yang ExampleA
menggunakan Singleton Config
bukanlah masalah, itu mungkin masih menjadi masalah dari sudut pandang pengujian. Benda-benda singleton akan membawa keadaan yang akan bertahan sampai penghentian aplikasi. Ini bisa menjadi masalah ketika menjalankan tes unit karena Anda ingin satu tes diisolasi dari yang lain (yaitu bahwa menjalankan satu tes seharusnya tidak mempengaruhi hasil yang lain). Untuk memperbaikinya, objek Singleton harus dihancurkan antara setiap uji coba (berpotensi harus me-restart seluruh aplikasi), yang mungkin memakan waktu (belum lagi membosankan dan menjengkelkan).
Setelah mengatakan ini, saya senang saya membuat kesalahan ini di sini dan tidak dalam penerapan aplikasi nyata. Bahkan, saya sebenarnya sedang mempertimbangkan untuk menulis ulang kode terbaru saya untuk menggunakan pola Singleton untuk beberapa kelas. Meskipun saya dapat dengan mudah mengembalikan perubahan (semuanya disimpan dalam SVN, tentu saja), saya masih akan membuang waktu untuk melakukannya.