Người độc thân . Khoảng 10-15 năm trước, độc thân là những thiết kế mẫu lớn để biết về. Tuy nhiên, ngày nay họ bị coi thường. Chúng dễ dàng hơn nhiều đối với đa luồng, nhưng bạn phải giới hạn việc sử dụng chúng ở một luồng tại một thời điểm, đây không phải lúc nào cũng là điều bạn muốn. Theo dõi cuộc sống cũng khó khăn như với các biến toàn cầu.
Một lớp singleton điển hình sẽ trông giống như thế này:
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!
}
Phụ thuộc tiêm (DI) . Điều này chỉ có nghĩa là truyền dịch vụ dưới dạng tham số hàm tạo. Một dịch vụ phải tồn tại để chuyển nó vào một lớp, vì vậy không có cách nào để hai dịch vụ dựa vào nhau; trong 98% các trường hợp, đây là những gì bạn muốn (và đối với 2% còn lại, bạn luôn có thể tạo một setWhatever()
phương thức và chuyển vào dịch vụ sau) . Do đó, DI không gặp vấn đề về khớp nối như các tùy chọn khác. Nó có thể được sử dụng với đa luồng, bởi vì mỗi luồng chỉ có thể có phiên bản riêng của mỗi dịch vụ (và chỉ chia sẻ những luồng mà nó thực sự cần). Nó cũng làm cho mã đơn vị có thể kiểm tra được, nếu bạn quan tâm đến điều đó.
Vấn đề với tiêm phụ thuộc là nó chiếm nhiều bộ nhớ hơn; bây giờ mọi phiên bản của một lớp cần tham chiếu đến mọi dịch vụ mà nó sẽ sử dụng. Ngoài ra, nó gây khó chịu khi sử dụng khi bạn có quá nhiều dịch vụ; có các khung làm giảm thiểu vấn đề này bằng các ngôn ngữ khác, nhưng do thiếu phản xạ của C ++, các khung DI trong C ++ có xu hướng thậm chí còn hiệu quả hơn là chỉ làm thủ công.
//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.
Xem trang này (từ tài liệu cho Ninject, khung C # DI) để biết ví dụ khác.
Tiêm phụ thuộc là giải pháp thông thường cho vấn đề này và là câu trả lời bạn sẽ thấy được đánh giá cao nhất cho các câu hỏi như thế này trên StackOverflow.com. DI là một kiểu đảo ngược của điều khiển (IoC).
Định vị dịch vụ . Về cơ bản, chỉ là một lớp chứa một thể hiện của mọi dịch vụ. Bạn có thể làm điều đó bằng cách sử dụng sự phản chiếu hoặc bạn chỉ có thể thêm một thể hiện mới vào nó mỗi khi bạn muốn tạo một dịch vụ mới. Bạn vẫn gặp vấn đề tương tự như trước đây - Làm thế nào để các lớp truy cập vào trình định vị này? - có thể được giải quyết theo bất kỳ cách nào ở trên, nhưng bây giờ bạn chỉ cần làm điều đó cho ServiceLocator
lớp của mình , thay vì cho hàng tá dịch vụ. Phương pháp này cũng có thể kiểm tra đơn vị, nếu bạn quan tâm đến loại điều đó.
Bộ định vị dịch vụ là một dạng khác của Inversion of Control (IoC). Thông thường, các khung làm việc tiêm phụ thuộc tự động cũng sẽ có một bộ định vị dịch vụ.
XNA (khung lập trình trò chơi C # của Microsoft) bao gồm một bộ định vị dịch vụ; để tìm hiểu thêm về nó, xem câu trả lời này .