2011-12-28 48 views
9

Trong chương thứ hai của cuốn sách Lập trình iOS của mình, Joe Conway mô tả bằng cách sử dụng 'self' trong các phương thức lớp trong trường hợp phân lớp con. Tôi hiểu khái niệm này và có một câu hỏi về vấn đề phân lớp.Làm cách nào để ghi đè đúng một phương thức lớp trong một Objective-C trong một lớp con?

Bối cảnh: Chúng tôi tạo ra một lớp Kiểm soát bóng mà phương pháp lớp + randomPossession trông như thế này:

+(id)randomPossession 
{ 
NSArray *randomAdjectiveList = [NSArray arrayWithObjects:@"Fluffy", @"Rusty", @"Shiny", nil]; 
NSArray *randomNounList = [NSArray arrayWithObjects:@"Bear", @"Spork", @"Mac", nil]; 

unsigned long adjectiveIndex = rand() % [randomAdjectiveList count]; 
unsigned long nounIndex = rand() % [randomNounList count]; 

NSString *randomName = [NSString stringWithFormat:@"%@ %@", [randomAdjectiveList objectAtIndex:adjectiveIndex], [randomNounList objectAtIndex:nounIndex]]; 

int randomValue = rand() % 100; 

NSString *randomSerialNumber = [NSString stringWithFormat:@"%c%c%c%c%c", 
           '0' + rand() % 10, 
           'A' + rand() % 10, 
           '0' + rand() % 10, 
           'A' + rand() % 10, 
           '0' + rand() % 10]; 

Possession *newPossession = [[self alloc] initWithPossessionName:randomName valueInDollars:randomValue serialNumber:randomSerialNumber]; 

return [newPossession autorelease]; 
} 

Tôi biết rằng giá trị trả thực sự cần là kiểu id mà id newPossession = ...

tôi subclassed Kiểm soát bóng và tạo ra một lớp được gọi là BallGlove bao gồm một Ivar mới, thương hiệu, một NSString *

tôi overrode các + randomPossession trong BallGlove như sau:

+(id)randomPossession 
{ 
BallGlove *myGlove = [super randomPossession]; 

NSArray *brandNames = [NSArray arrayWithObjects:@"Rawlings", @"Mizuno", @"Wilson", nil]; 

unsigned long randomNameIndex = rand() % [brandNames count]; 

[myGlove setBrandName:[brandNames objectAtIndex:randomNameIndex]]; 

NSLog(@"myGlove is of type class: %@", [self class]); 

return myGlove; 
} 

Câu hỏi của tôi là: Cách thức tôi vượt qua phương pháp lớp này phù hợp và được chấp nhận bởi cộng đồng (tức là song song định dạng -init bằng cách chụp siêu thực hiện trong một biến, thao tác biến cho phù hợp và sau đó trả về nó? Đầu ra của tôi cho thấy rằng đối tượng được trả về là một thể hiện của BallGlove tuy nhiên, tôi đã quan tâm đến việc thực thi có thể chấp nhận được. Cảm ơn trước.

Trả lời

0

Về mặt kỹ thuật, điều đó là ok.

Tôi muốn đề xuất phương án thay thế. Nếu bạn đã có một bộ khởi tạo công khai được chỉ định trên lớp cơ sở (mà bạn có thể muốn tạo và gọi từ phương thức lớp của nhà máy đó), và sau đó sử dụng bộ khởi tạo đó (hoặc thậm chí một bộ khởi tạo mới từ lớp con của bạn) trong lớp con của bạn phương pháp.

Đó không phải là mã nhiều hơn, nhưng theo ý kiến ​​của tôi dễ theo dõi hơn và chứng minh trong tương lai. Trình khởi tạo có thể có ích ở một thời điểm, nhưng tất nhiên đây không phải là giải pháp cho mọi ứng dụng.

+0

+ randomPossession trong lớp cơ sở trong thực tế gọi initializer được chỉ định. Phương thức lớp cũng tạo ra các giá trị "ngẫu nhiên" cho bộ khởi tạo đó. Nếu tôi làm những gì tôi tin rằng bạn đang gợi ý, tôi sẽ phải sao chép mã cho các giá trị "ngẫu nhiên" trong phương thức lớp đã ghi đè (+ randomPossession) cũng như ghi đè trình khởi tạo được chỉ định để gọi trình khởi tạo mới của lớp BallGlove, thêm thông tin iVar bổ sung của tôi. Tại sao lại ghi đè phương pháp lớp học khi tôi đề xuất bất lợi theo nghĩa chung? Nó không thể được so sánh với chuỗi khởi tạo? –

+0

Tôi không nghĩ rằng nó quá xấu xí - nó không chỉ là một mô hình rất phổ biến. Câu hỏi chính nó là một chỉ báo tốt cho điều đó. :) Một điều có chút mơ hồ với phân lớp là tên của phương thức, và việc đặt tên tốt là một trong những điều tốt nhất về mục tiêu-c. Vì vậy, trong trường hợp của bạn, một phương thức + randomBallGlove có thể tốt hơn là ghi đè. – Eiko

+0

Bạn đang gợi ý rằng tôi thay vì tạo một phương thức lớp có tên là + randomBallGlove bao gồm việc thực hiện + randomPossession ngoài việc triển khai tùy chỉnh mong muốn? Nghe hay đấy. Bạn đề xuất gì cho + randomPossession vẫn có sẵn cho các lớp con của Possession? ghi đè lên phương pháp và có nó ném một ngoại lệ chỉ đạo sử dụng + randomBallGlove? Đây có phải là giao thức bình thường của các sự kiện như vậy không?Tôi biết ví dụ này có thể không tồn tại trong thực tế, tôi chỉ học hỏi và tò mò muốn chấp nhận thực hiện trong trường hợp nó xảy ra. Cảm ơn bạn đã giúp đỡ! –

1

Có, bạn có thể thực hiện việc khởi tạo như vậy. Trong thực tế đó là cách nó được thực hiện trong hầu hết các trường hợp. Ý tôi là, đó là lý do để kế thừa từ một lớp siêu hạng nhất. Bạn muốn thứ ngoài những gì có trong lớp siêu. Vì vậy, bạn chèn mã vào bất cứ điều gì là cụ thể cho lớp kế thừa và nó nên được thực hiện theo cách đó.

Tôi nghĩ cách bạn muốn đối tượng được khởi tạo BallGlove cũng là một yếu tố trong cách bạn xác định phương pháp kế thừa của mình. Câu hỏi đặt ra là gọi số Possession init hoặc gọi số BallGlove init (Không phải việc tạo một thể hiện của một lớp là nơi duy nhất để sử dụng một phương thức lớp). Vì vậy, nó đi xuống đến logic của việc tạo ra các đối tượng của bạn, tức là bạn đang mô tả đối tượng BallGlove như thế nào là bạn đảm bảo rằng phương thức lớp của bạn mô tả nó theo cách phù hợp với tiêu chí đối tượng BallGlove và không trở thành đối tượng chung Possession. Câu trả lời của tôi là nếu bạn có thể thực hiện nó đúng, sử dụng một dòng song song của các phương thức lớp là chấp nhận được.

Ngoài ra, nó không quan trọng nếu bạn đang trở về kiểu Possession trong lớp siêu của bạn bởi vì, id có thể trỏ đến một đối tượng của bất kỳ kiểu lớp

+0

Cảm ơn bạn đã trả lời. Điều đó không thực sự trả lời câu hỏi. Câu hỏi liên quan đến định dạng ghi đè các phương thức lớp. Ngoài sự cần thiết của việc tạo ra một phương thức thuận tiện cho một lớp con, tôi không chắc chắn về một lý do để ghi đè phương thức lớp. Như vậy, tôi chưa thấy bất cứ điều gì về điều này. Có bất kỳ ví dụ nào xác minh rằng định dạng tôi đã sử dụng là phù hợp không? –

+0

@BrianPalma Tôi xin lỗi. Có lẽ tôi đã không trả lời đúng. Tôi không thực sự thấy lý do tại sao nó không được chấp nhận để làm điều đó cho các phương pháp lớp học giống như cách khởi tạo. Cách tôi hình dung nó hoạt động là, các phương thức lớp có xu hướng gọi các phương thức init, thực hiện một số mã và trả về một phiên bản tự động phát hành là những gì bạn đang làm. Tôi không biết nếu có những ví dụ để xác minh định dạng của bạn, nhưng tôi cũng không thể thấy bất kỳ vấn đề nào có thể phát sinh từ nó. Hãy để tôi kiểm tra một số mã mẫu và lấy lại cho bạn. – MadhavanRP

2

Yep, đó là một cách hoàn toàn hợp lý để làm điều đó. Không có gì đặc biệt khác biệt giữa các phương thức lớp và các phương thức thông thường - chỉ một phương thức được thực hiện bởi một lớp và lớp kia được thực hiện bởi một cá thể.

2

Thời điểm bạn ghi đè lên một phương pháp lớp học mà bạn có thể quyết định triển khai nó với sự trợ giúp của việc triển khai siêu hoặc không có nó. Điều đó hoàn toàn tùy vào bạn. Overiding init là một câu chuyện hoàn toàn khác biệt, không chỉ vì nó là một phương thức thể hiện mà bởi vì nó có một quy ước/hợp đồng liên kết với nó. Hãy nhớ rằng đối với các phương pháp ví dụ, nguyên tắc Subtitution Liskov không nên bị vi phạm.

Việc ghi đè phương pháp lớp học của bạn là hoàn toàn tốt, mặc dù tôi sẽ xem xét việc đánh lừa các phương thức lớp một mùi thiết kế. Mặc dù nó rất tốt trong Objective-C, nó không phải bằng các ngôn ngữ khác và vì một lý do rất tốt. Tính đa hình như một khái niệm được ràng buộc tốt hơn với các cá thể có thể được sử dụng như là các sản phẩm thay thế cho nhau, trong khi sử dụng các phương thức lớp phá vỡ khái niệm (nghĩa là không có sự phân bổ thực).Đó là thông minh, nhưng không cần thiết trực quan và linh hoạt.

+0

Cảm ơn bạn đã trả lời. Như tôi đã đề cập dưới đây, tôi không biết bất kỳ việc sử dụng nào ghi đè một phương thức lớp cụ thể trong một lớp con, khác với ít mã hơn trong một phương thức tiện lợi. Tại thời điểm này, tôi không có ý định làm như vậy. Tôi chỉ tò mò muốn thực hiện đúng nếu tình hình nảy sinh. –

+0

@BrianPalma: Có nhiều lý do để ghi đè lên các phương thức lớp học ngoài "phương pháp tiện lợi". Ví dụ, các phương thức lớp 'defaultMenu' và' requiresConstraintBasedLayout' của NSView tồn tại chỉ để được ghi đè. – Chuck

+0

@Chuck Xin lỗi, tôi nghĩ rằng tôi đã bỏ lỡ hoặc chỉ là quá mới! Ý tôi là "các phương pháp tiện lợi" về các đối tượng mô hình. Tôi hiểu rằng có các phương thức lớp trong iOS và OS X tồn tại hoàn toàn để được ghi đè và yêu cầu [super someClassMethodHere]; –

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