Kita semua tahu betapa buruknya para Lajang karena mereka menyembunyikan ketergantungan dan untuk alasan lain .
Namun dalam kerangka kerja, mungkin ada banyak objek yang perlu dibuat instantiated hanya sekali dan dipanggil dari mana saja (logger, db, dll).
Untuk mengatasi masalah ini saya telah diberitahu untuk menggunakan apa yang disebut "Objects Manager" (atau Service Container seperti symfony) yang secara internal menyimpan setiap referensi ke Services (logger dll).
Tetapi mengapa Penyedia Layanan tidak seburuk Singleton murni?
Penyedia layanan juga menyembunyikan dependensi dan mereka hanya menyelesaikan pembuatan istance pertama. Jadi saya benar-benar berjuang untuk memahami mengapa kita harus menggunakan penyedia layanan daripada lajang.
PS. Saya tahu bahwa untuk tidak menyembunyikan dependensi saya harus menggunakan DI (seperti yang dinyatakan oleh Misko)
Menambahkan
Saya akan menambahkan: Akhir-akhir ini para lajang tidak seburuk itu, pencipta PHPUnit menjelaskannya di sini:
DI + Singleton memecahkan masalah:
<?php
class Client {
public function doSomething(Singleton $singleton = NULL){
if ($singleton === NULL) {
$singleton = Singleton::getInstance();
}
// ...
}
}
?>
itu cukup pintar meskipun ini tidak menyelesaikan sama sekali setiap masalah.
Selain DI dan Service Container , adakah solusi yang baik untuk mengakses objek helper ini?
sumber
Jawaban:
Service Locator adalah salah satu dari dua kejahatan yang bisa dikatakan. Yang "lebih rendah" yang mengarah ke empat perbedaan ini ( setidaknya saya tidak dapat memikirkan yang lain sekarang ):
Prinsip Tanggung Jawab Tunggal
Service Container tidak melanggar Prinsip Tanggung Jawab Tunggal seperti yang dilakukan Singleton. Singletons menggabungkan pembuatan objek dan logika bisnis, sedangkan Service Container bertanggung jawab secara ketat untuk mengelola siklus hidup objek aplikasi Anda. Dalam hal ini Service Container lebih baik.
Kopel
Singletons biasanya di-hardcode ke dalam aplikasi Anda karena panggilan metode statis, yang mengarah ke dependensi yang berpasangan erat dan sulit untuk dipalsukan dalam kode Anda. SL di sisi lain hanyalah satu kelas dan dapat disuntikkan. Jadi, sementara semua kelas Anda akan bergantung padanya, setidaknya itu adalah dependensi yang digabungkan secara longgar. Jadi, kecuali Anda menerapkan ServiceLocator sebagai Singleton itu sendiri, itu agak lebih baik dan juga lebih mudah untuk diuji.
Namun, semua kelas yang menggunakan ServiceLocator sekarang akan bergantung pada ServiceLocator, yang juga merupakan bentuk penggandengan. Ini dapat dikurangi dengan menggunakan antarmuka untuk ServiceLocator sehingga Anda tidak terikat ke implementasi ServiceLocator konkret tetapi kelas Anda akan bergantung pada keberadaan semacam Locator sedangkan tidak menggunakan ServiceLocator sama sekali meningkatkan penggunaan kembali secara dramatis.
Dependensi Tersembunyi
Masalah menyembunyikan ketergantungan sangat banyak muncul. Saat Anda baru saja memasukkan locator ke kelas konsumsi Anda, Anda tidak akan tahu dependensi apa pun. Namun berbeda dengan Singleton, SL biasanya akan membuat instance semua dependensi yang dibutuhkan di balik layar. Jadi, ketika Anda mengambil Layanan, Anda tidak berakhir seperti Misko Hevery dalam contoh CreditCard , misalnya Anda tidak perlu membuat contoh semua ketergantungan dependensi dengan tangan.
Mengambil dependensi dari dalam instance juga melanggar Law of Demeter , yang menyatakan bahwa Anda tidak boleh menggali kolaborator. Sebuah instance hanya boleh berbicara dengan kolaborator langsungnya. Ini masalah dengan Singleton dan ServiceLocator.
Status Global
Masalah Status Global juga agak berkurang karena ketika Anda membuat contoh Service Locator baru antara tes semua contoh yang dibuat sebelumnya akan dihapus juga (kecuali Anda membuat kesalahan dan menyimpannya dalam atribut statis di SL). Itu tidak berlaku untuk kondisi global mana pun di kelas yang dikelola oleh SL, tentu saja.
Juga lihat Fowler di Service Locator vs Dependency Injection untuk diskusi yang lebih mendalam.
Catatan tentang pembaruan Anda dan artikel yang ditautkan oleh Sebastian Bergmann tentang kode pengujian yang menggunakan Singletons : Sebastian sama sekali tidak menyarankan bahwa solusi yang diusulkan membuat penggunaan Singleons tidak terlalu menjadi masalah. Ini hanyalah satu cara untuk membuat kode yang tidak mungkin diuji lebih dapat diuji. Tapi itu masih kode bermasalah. Bahkan, dia secara eksplisit mencatat: "Hanya Karena Anda Bisa, Tidak Berarti Anda Harus".
sumber
Pola pencari lokasi merupakan anti-pola. Itu tidak memecahkan masalah mengekspos dependensi (Anda tidak dapat membedakan dari definisi kelas apa dependensinya karena mereka tidak diinjeksi, sebaliknya mereka ditarik keluar dari pencari layanan).
Jadi, pertanyaan Anda adalah: mengapa pencari lokasi baik? Jawaban saya adalah: tidak.
Hindari, hindari, hindari.
sumber
Kontainer layanan menyembunyikan dependensi seperti yang dilakukan pola Singleton. Anda mungkin ingin menyarankan menggunakan wadah injeksi ketergantungan sebagai gantinya, karena ia memiliki semua keuntungan dari wadah layanan namun tidak ada (sejauh yang saya tahu) kerugian yang dimiliki wadah layanan.
Sejauh yang saya pahami, satu-satunya perbedaan antara keduanya adalah bahwa dalam wadah layanan, wadah layanan adalah objek yang disuntikkan (sehingga menyembunyikan ketergantungan), ketika Anda menggunakan DIC, DIC menyuntikkan dependensi yang sesuai untuk Anda. Kelas yang dikelola oleh DIC sama sekali tidak menyadari fakta bahwa ia dikelola oleh DIC, sehingga Anda memiliki lebih sedikit kopling, ketergantungan yang jelas, dan pengujian unit yang menyenangkan.
Ini adalah pertanyaan yang bagus di SO menjelaskan perbedaan keduanya: Apa perbedaan antara pola Injeksi Ketergantungan dan Lokasi Layanan?
sumber
Karena Anda dapat dengan mudah mengganti objek di Service Container dengan
1) pewarisan (kelas Object Manager dapat diwariskan dan metode dapat diganti)
2) mengubah konfigurasi (dalam kasus dengan Symfony)
Dan, Singletons buruk bukan hanya karena koplingnya yang tinggi, tetapi karena mereka adalah _ Single _tons. Itu arsitektur yang salah untuk hampir semua jenis objek.
Dengan DI 'murni' (dalam konstruktor) Anda akan membayar harga yang sangat besar - semua objek harus dibuat sebelum diteruskan dalam konstruktor. Ini berarti lebih banyak memori yang digunakan dan lebih sedikit kinerja. Selain itu, tidak selalu objek hanya dapat dibuat dan diteruskan dalam konstruktor - rantai dependensi dapat dibuat ... Bahasa Inggris saya tidak cukup baik untuk membahasnya secara lengkap, baca tentangnya di dokumentasi Symfony.
sumber
Bagi saya, saya mencoba menghindari konstanta global, lajang karena alasan sederhana, ada beberapa kasus ketika saya mungkin perlu menjalankan API.
Misalnya, saya memiliki front-end dan admin. Di dalam admin, saya ingin mereka dapat masuk sebagai pengguna. Pertimbangkan kode di dalam admin.
$frontend = new Frontend(); $frontend->auth->login($_GET['user']); $frontend->redirect('/');
Ini dapat membuat koneksi database baru, logger baru dll untuk inisialisasi frontend dan memeriksa apakah pengguna benar-benar ada, valid dll. Ini juga akan menggunakan cookie terpisah dan layanan lokasi yang tepat.
Ide saya tentang singleton adalah - Anda tidak dapat menambahkan objek yang sama di dalam induk dua kali. Contohnya
$logger1=$api->add('Logger'); $logger2=$api->add('Logger');
akan meninggalkan Anda dengan satu instance dan kedua variabel yang mengarah ke sana.
Akhirnya jika Anda ingin menggunakan pengembangan berorientasi objek, maka bekerjalah dengan objek, bukan dengan kelas.
sumber
$api
var di sekitar kerangka Anda? Saya tidak mengerti apa yang Anda maksud. Juga jika panggilanadd('Logger')
mengembalikan contoh yang sama pada dasarnya Anda memiliki wadah layanan