2010-01-20 37 views
26

Tôi đang cố gắng để tạo ra một nhà máy (design pattern) trong Objective C Vì vậy, tôi đang làm một cái gì đó như:Factory (design pattern) trong Objective C

+ (Car *)createCar:(int)color { 
    if (color == 1) { 
     return [CarFactory createBlueCar]; 
    } else if (color == 2) { 
     return [CarFactory createRedCar]; 
    } else { 
     return nil; 
    } 
} 

+ (Car *)createBlueCar { 
    // ... 
} 

+(Car*)createRedCar{ 
    // ... 
} 

Tuy nhiên tôi không muốn createBlueCarcreateRedCar có sẵn cho công chúng và nếu tôi không xác định chúng trong tệp .h thì tôi sẽ nhận được cảnh báo về định nghĩa bị thiếu.

Tôi là một nhà phát triển Java cũ và một newbie trong Objective-C - Vì vậy, nó có thể chỉ là thực hành xấu Nếu vậy thực hành tốt là làm như thế.

+2

Bạn thường không có các lớp Nhà máy trong Mục tiêu-C vì các lớp là đối tượng lớp đầu tiên. Nhìn vào các lớp Umbrella như NSPredicate hoặc NSNumber. Họ là những nhà máy. Bạn thường sẽ nhận được một lớp con của NSPredicate hoặc NSNumber được trả lại. –

+2

Đồng ý với @AdamSmith, cách tốt nhất để làm điều đó sẽ là phương pháp lớp học trên Xe hơi, ví dụ: '+ (Car *) carWithColor: (int) color;' – dmur

+0

Thực ra tôi nhận thấy một thứ khác có thể không rõ ràng khi bắt đầu từ Java. Nếu "createCar" là trên lớp thực hành tốt nhất CarFactory thường là viết [self createBlueCar]. Trong các lớp ObjC là các đối tượng không giống như Java. Vì vậy, tự trong một lớp học phương pháp đề cập đến các đối tượng lớp (CarFactory trong trường hợp này).Lý do sử dụng "tự" là mã sẽ không bị hỏng nếu bạn kế thừa "CarFactory" và thực hiện lại ví dụ: "createBlueCar" –

Trả lời

49

Cách tốt nhất để làm điều này là với Tiện ích mở rộng lớp học.

.h

@interface MyClass : NSObject 
@property(readonly) BOOL publiclyReadOnlyPrivatelyWritableFlag; 
+ (id) myExposedFactoryMethod; 
@end 

.m

#import "MyClass.h" 

@interface MyClass() 
@property(readwrite) BOOL publiclyReadOnlyPrivatelyWritableFlag; 
+ (id) privateMethod1; 
+ (id) privateMEthod2; 
@end 

@implementation MyClass 
@synthesize publiclyReadOnlyPrivatelyWritableFlag; // no ivar -- only works in 64 bit and iPhone 
+ (id) myExposedFactoryMethod 
{ 
    ... 
    [self privateMethod1]; 
    ... 
} 

+ (id) privateMethod1; 
{ 
    return ... 
} 

+ (id) privateMEthod2; 
{ 
    return ... 
} 
@end 

Một phần mở rộng lớp là một giải pháp tốt hơn bởi vì nó là một phần mở rộng thực sự của giao diện của lớp trong khi một chủng loại (không có tương ứng thực hiện) chỉ đơn thuần là một gợi ý rằng lớp thực hiện các phương thức. Đó là, trình biên dịch sẽ cảnh báo nếu bạn không thực hiện giao diện - các phương thức - được khai báo trong phần mở rộng của lớp, nhưng sẽ không cảnh báo nếu bạn đã làm như vậy với một thể loại được đặt tên.

Cũng lưu ý rằng tiện ích mở rộng lớp cho phép bạn nâng cấp thuộc tính readonly thành thuộc tính readwrite theo ví dụ trên.

+2

+1 Điều này thực sự là câu trả lời được chấp nhận, vì nó thể hiện cách thực hiện và chính xác lý do tại sao. –

4

Tôi nghĩ bạn có thể thêm chúng vào lớp bằng cách sử dụng objective-c category trong tệp triển khai (không phải giao diện) như một cách mô phỏng các phương thức riêng nếu bạn muốn "ẩn" chúng khỏi người dùng trong lớp của bạn.

Lưu ý, mặc dù bạn sẽ không còn quảng cáo các phương thức cho khách hàng của lớp học nữa, họ vẫn sẽ có thể sử dụng chúng nếu họ sử dụng bộ chọn chính xác. Ngoài ra, họ luôn có thể sử dụng một cái gì đó như classdump để tạo lại giao diện đầy đủ cho lớp học của bạn để các phương pháp của bạn sẽ không bao giờ thực sự được ẩn.

Xem this question để biết thêm ví dụ về cách tạo phương pháp "riêng tư" trong mục tiêu-c.

+0

nhưng sau đó tôi sẽ có "ẩn" tệp h chứa danh mục –

+2

@Guy: không, bạn có thể triển khai danh mục đầy đủ trong tệp triển khai. Không có gì để nói phần @interface phải nằm trong tệp .h. – jkp

+1

@Guy JKP là đúng, bạn đặt nó ở trên cùng của .m, đó là thực hành khá chuẩn. Hãy nhớ rằng: không bao giờ có bất kỳ điều gì riêng tư trong mục tiêu-c, chỉ ẩn hoặc chưa biết – slf

-1

Bạn có thể tạo một private static chức năng

@implementation Car 

static createBlueCar() { 
    .... 
} 

+(Car*) createCar:(int) color{ 
    if (color==1) { 
    return createBlueCar(); 
    } ... 
} 

@end 

nhưng không có, bạn không thể tạo ra một sự thật riêng viên. (Bạn có thể gọi một số quy ước, ví dụ: +(Car*)private_createCar trong danh mục riêng tư để ngăn cản việc sử dụng nó.)