Lajang . Sekitar 10-15 tahun yang lalu, lajang yang satu desain-pola besar untuk tahu tentang. Namun, saat ini mereka dipandang rendah. Mereka jauh lebih mudah untuk multi-utas, tetapi Anda harus membatasi penggunaannya pada satu utas pada satu waktu, yang tidak selalu seperti yang Anda inginkan. Melacak masa hidup sama sulitnya dengan variabel global.
Kelas singleton tipikal akan terlihat seperti ini:
class MyClass
{
private:
static MyClass* _instance;
MyClass() {} //private constructor
public:
static MyClass* getInstance();
void method();
};
...
MyClass* MyClass::_instance = NULL;
MyClass* MyClass::getInstance()
{
if(_instance == NULL)
_instance = new MyClass(); //Not thread-safe version
return _instance;
//Note that _instance is *never* deleted -
//it exists for the entire lifetime of the program!
}
Ketergantungan Injeksi (DI) . Ini hanya berarti melewatkan layanan sebagai parameter konstruktor. Suatu layanan harus sudah ada untuk lulus ke dalam kelas, jadi tidak ada cara bagi dua layanan untuk saling bergantung; dalam 98% kasus, inilah yang Anda inginkan (dan untuk 2% lainnya, Anda selalu dapat membuat setWhatever()
metode dan meneruskan layanan nanti) . Karena itu, DI tidak memiliki masalah kopling yang sama dengan opsi lainnya. Ini dapat digunakan dengan multithreading, karena setiap utas hanya dapat memiliki contoh sendiri dari setiap layanan (dan hanya berbagi yang benar-benar perlu). Itu juga membuat kode unit dapat diuji, jika Anda peduli tentang itu.
Masalah dengan injeksi ketergantungan adalah ia membutuhkan lebih banyak memori; sekarang setiap instance kelas membutuhkan referensi ke setiap layanan yang akan digunakan. Juga, itu akan mengganggu untuk digunakan ketika Anda memiliki terlalu banyak layanan; ada kerangka kerja yang mengurangi masalah ini dalam bahasa lain, tetapi karena kurangnya refleksi C ++, kerangka kerja DI di C ++ cenderung lebih berfungsi daripada hanya melakukannya secara manual.
//Example of dependency injection
class Tower
{
private:
MissileCreationService* _missileCreator;
CreepLocatorService* _creepLocator;
public:
Tower(MissileCreationService*, CreepLocatorService*);
}
//In order to create a tower, the creating-class must also have instances of
// MissileCreationService and CreepLocatorService; thus, if we want to
// add a new service to the Tower constructor, we must add it to the
// constructor of every class which creates a Tower as well!
//This is not a problem in languages like C# and Java, where you can use
// a framework to create an instance and inject automatically.
Lihat halaman ini (dari dokumentasi untuk Ninject, kerangka kerja C # DI) untuk contoh lain.
Injeksi ketergantungan adalah solusi yang biasa untuk masalah ini, dan merupakan jawaban yang akan Anda lihat paling terunggulkan untuk pertanyaan seperti ini di StackOverflow.com. DI adalah jenis Pembalikan Kontrol (IoC).
Pencari Lokasi Layanan . Pada dasarnya, hanya kelas yang menyimpan instance dari setiap layanan. Anda dapat melakukannya menggunakan refleksi , atau Anda bisa menambahkan contoh baru ke dalamnya setiap kali Anda ingin membuat layanan baru. Anda masih memiliki masalah yang sama seperti sebelumnya - Bagaimana kelas mengakses locator ini? - yang dapat diselesaikan dengan salah satu cara di atas, tetapi sekarang Anda hanya perlu melakukannya untuk ServiceLocator
kelas Anda , bukan untuk puluhan layanan. Metode ini juga dapat diuji unit, jika Anda peduli tentang hal semacam itu.
Service Locators adalah bentuk lain dari Inversion of Control (IoC). Biasanya, kerangka kerja yang melakukan injeksi dependensi otomatis juga akan memiliki pelacak layanan.
XNA (kerangka kerja pemrograman game C # Microsoft) mencakup pelacak layanan; untuk mempelajari lebih lanjut, lihat jawaban ini .