Сінглтон . Близько 10-15 років тому, одинаки були великий дизайн-шаблон , щоб знати. Однак сьогодні вони придивляються. Їх набагато простіше багатопотоково, але ви повинні обмежити їх використання однією ниткою за раз, що не завжди є тим, що ви хочете. Відстеження життя так само важко, як і з глобальними змінними.
Типовий клас одиночки буде виглядати приблизно так:
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!
}
Вприскування в залежності (DI) . Це просто означає передачу послуги в якості параметра конструктора. Служба повинна вже існувати для того, щоб передати її в клас, тому немає можливості, щоб дві служби покладалися один на одного; у 98% випадків це те, що ви хочете (а для інших 2% ви завжди можете створити setWhatever()
метод і пізніше перейти в службу) . Через це у DI немає таких самих проблем, як інші варіанти. Він може використовуватися з багатопотоковою читанням, оскільки кожен потік може просто мати власний екземпляр кожної служби (і ділитися лише тими, які йому абсолютно потрібні). Це також робить модуль коду, який можна перевірити, якщо вам це важливо.
Проблема введення залежностей полягає в тому, що вона займає більше пам’яті; тепер кожен екземпляр класу потребує посилань на кожну службу, яку він буде використовувати. Крім того, це стає прикро використовувати, коли у вас занадто багато послуг; є рамки, які пом'якшують цю проблему іншими мовами, але через відсутність відображення C ++ рамки DI в C ++, як правило, навіть більше роботи, ніж просто робити це вручну.
//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.
Дивіться цю сторінку (з документації для Ninject, рамку C # DI) для іншого прикладу.
Ін'єкція залежностей є звичайним рішенням цієї проблеми, і це відповідь, яку ви побачите на StackOverflow.com. DI - це тип інверсії управління (IoC).
Service Locator . В основному, просто клас, який містить екземпляр кожної служби. Ви можете це зробити за допомогою відображення або просто додати новий екземпляр до нього кожного разу, коли ви хочете створити нову послугу. Ви все ще маєте ту саму проблему, що і раніше - Як класи отримують доступ до цього локатора? - який можна вирішити будь-яким із перерахованих вище способів, але тепер це потрібно робити лише для вашого ServiceLocator
класу, а не для десятків послуг. Цей метод також перевіряється на рівні одиниць, якщо ви дбаєте про такі речі.
Локатори обслуговування - це ще одна форма інверсії управління (IoC). Зазвичай рамки, які виконують автоматичне введення залежності, також матимуть сервіс-локатор.
XNA (Microsoft C # для програмування ігор) включає в себе локатор обслуговування; щоб дізнатися більше про це, дивіться цю відповідь .