2012-09-27 29 views
8

Tôi có 2 lớp con kế thừa từ 'MyClass' và mỗi lớp con phải là một singleton.Tạo một lớp singleton với dispatch_once cho lớp hiearchy

Tôi đã sử dụng mô hình này để nhận một trường hợp tĩnh khi tôi không có bất kỳ lớp khác kế thừa:

+ (MyClass *)getInstance 
{ 
    static dispatch_once_t once; 
    static MyClass *instance; 

    dispatch_once(&once, ^{ 
     instance = [[MyClass alloc] init]; 
    }); 

    return instance; 
} 

này hoạt động chỉ là tuyệt vời. Bây giờ, nếu tôi thêm hai lớp con mới, FirstClass và SecondClass, cả hai đều kế thừa từ MyClass, làm thế nào để đảm bảo rằng tôi lấy lại ChildClass tương ứng?

dispatch_once(&once, ^{ 
    // No longer referencing 'MyClass' and instead the correct instance type 
    instance = [[[self class] alloc] init]; 
}); 

FirstClass *firstClass = [FirstClass getInstance]; // should be of FirstClass type 
SecondClass *secondClass = [SecondClass getInstance]; // should be of SecondClass type 

Làm ở trên có nghĩa là tôi luôn nhận lại bất cứ điều gì lớp tôi instantiated 1st as type lớp thứ hai của tôi:

first: <FirstClass: 0x884b720> 
second: <FirstClass: 0x884b720> 
// Note that the address and type as identical for both. 

gì là cách tốt nhất để tạo ra các độc thân lớp con tương ứng mà không cần thêm getInstance phương pháp để mỗi lớp con?

Trả lời

6

Trừ khi bạn có lý do chính đáng, thông thường bạn nên tránh phân lớp đơn. Nó tạo ra một tình huống rất khó hiểu. Nếu bạn tạo một singleton MyClass, bạn có thể tạo một singleton FirstClass không? Vì FirstClass phải luôn có thể sử dụng được ở bất cứ đâu MyClass có thể sử dụng được (bởi Liskov), hiện tại có ba đối tượng "singleton" MyClass. Bây giờ ObjC là rất lỏng lẻo với người độc thân, và đó là một điều tốt, nhưng điều này vẫn còn rất lạ.

OK, điều đó nói lên, còn vấn đề của bạn thì sao? Đầu tiên là giải pháp, sau đó là câu trả lời. Giải pháp là MyClass có lẽ không nên là một singleton, như đã thảo luận ở trên. Loại bỏ getInstance trong lớp cha và chỉ định nghĩa nó trong các lớp con.

Câu trả lời cho những gì đang diễn ra trong số dispatch_once của bạn. Bạn đang truyền cùng một mã thông báo tĩnh once tĩnh trong mọi trường hợp. dispatch_once sẽ chạy không quá một lần bao giờ cho một mã thông báo đã cho. Cách duy nhất xung quanh việc này là chuyển các mã thông báo khác nhau cho mỗi lớp và tôi không biết cách thuận tiện để làm điều đó mà không sao chép mã dispatch_once trong mỗi tệp. Bạn có thể cố gắng tạo các mã thông báo once khác nhau cho từng phân lớp, nhưng đó có thể là nhiều rắc rối và mã hơn là chỉ sao chép phương thức sharedInstance.

BTW, không gọi số getInstance. "get" có ý nghĩa đặc biệt trong ObjC, và bạn không có ý nghĩa ở đây, do đó, nó gây nhầm lẫn. Điều này thường được gọi là sharedInstance hoặc tốt hơn sharedSomething trong đó "một cái gì đó" là lớp học của bạn.Nếu bạn thực sự có nghĩa là phải có một MyClass và phải có một FirstClass và phải có một SecondClass, bạn có thể thực hiện sharedInstance trong cả ba.

+0

Lý do tôi có cấu trúc phân cấp này là tôi có số lượng mã và dữ liệu chung được chia sẻ mà tất cả các lớp con của tôi có (bên ngoài 'sharedInstance'. Đây cũng là lý do tại sao tôi sử dụng các giao thức kế thừa vs. không lặp lại cùng một mã khởi tạo cho cả ba lớp bắt nguồn –

+0

+1 về cách đặt tên "get". –

1

bạn biết đơn là gnarly, phải không? nhiều người độc thân là một vấn đề lớn hơn. hết sức thận trọng.


bạn chỉ có thể sử dụng dispatch_once để tạo singleton cơ bản. thì cơ sở của bạn có thể giữ một bản đồ (ví dụ: từ điển {key: ClassName | value: Instance}) của các loại có nguồn gốc của nó.

mà bạn đang sử dụng dispatch_once đề xuất điều này sẽ được sử dụng trong ngữ cảnh đa luồng. trong trường hợp đó, bạn sẽ cần phải bảo vệ tương tác với từ điển bằng cách sử dụng một mutex.

thì thư của bạn từ các lớp con sẽ xác định dựa trên lớp nhắn tin (self) mà lớp cần tra cứu (tạo ví dụ đó, nếu cần).

+1

dân phải học cách sử dụng độc thân và sau đó có được screwed bởi họ biết lý do tại sao bạn có nghĩa là bởi họ một 'vấn đề lớn hơn'. – mskw

+0

@mskw tôi không muốn đập kinh thánh quá khó, khi hầu hết mọi người đã nghe câu đầu tiên = p nhưng bạn nói đúng. một vấn đề điển hình là việc xóa bỏ toàn cầu/singleton ảnh hưởng đến nhiều nguồn/triển khai. khi nhiều người tương tác, nó trở thành một trạng thái toàn cầu đan xen lớn mà thường không thể tái sử dụng theo cách khác với ý định ban đầu (IOW, để tách biệt). điều đó có nghĩa là nhiều người trong số các lớp và phụ thuộc đó, không chỉ là những người độc thân, mà cả những triển khai sử dụng chúng, không thể sử dụng được cho các chương trình khác - sửa chữa mất nhiều thời gian và nhiều thử nghiệm. – justin

0

sử dụng id trong bạn myClass trong Firstclass như thế này

+(instancetype)sharedInstance 
{ 
    static id sharedInstance; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     sharedInstance = [[[self class] alloc] init]; 
    }); 
    return sharedInstance; 
} 

tôi nghĩ rằng điều này sẽ làm việc

Các vấn đề liên quan