2011-12-28 10 views
9

W drugim rozdziale książki o programowaniu w iOS Joe Conway opisuje użycie "ja" w metodach klasowych w przypadku podklasy. Rozumiem tę koncepcję i mam pytanie dotyczące kwestii podklasy.Jak poprawnie zastąpić metodę klasy w Objective-C w podklasie?

Tło: My stworzyliśmy klasę Possession którego metoda klasy + randomPossession wygląda tak:

+(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]; 
} 

Jestem świadomy, że wartość zwracana naprawdę powinny być typu id tak, że id newPossession = ...

i podklasy Possession i stworzył klasę o nazwie BallGlove które obejmowały nową Ivar, marką, NSString *

i overrode + randomPossession w BallGlove następująco:

+(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; 
} 

Moje pytanie brzmi następująco: Czy sposób, w jaki przeważyłem tę metodę klasy, jest odpowiedni i akceptowany przez społeczność (tj. równolegle do formatu -init przechwytując super implementację w zmiennej, odpowiednio manipulować zmienną, a następnie ją zwrócić? Moje wyniki pokazują, że zwracany obiekt jest instancją BallGlove, ale byłem zainteresowany akceptowalną implementacją. Z góry dziękuję.

Odpowiedz

0

Jest technicznie w porządku.

Proponuję jednak alternatywę. Jeśli masz już wyznaczony publiczny inicjator w twojej klasie bazowej (który i tak będziesz chciał utworzyć i wywołać z tej metody klasy fabrycznej), a następnie użyj tego samego inicjalizatora (lub nawet nowego z twojej podklasy) w swojej klasie podklas metoda.

To niewiele więcej kodu, ale moim zdaniem łatwiejsze do śledzenia i przyszłościowe. Inicjator może się przydać w pewnym momencie, ale oczywiście nie jest to rozwiązanie dla każdej aplikacji.

+0

+ randomPosesja w klasie bazowej w rzeczywistości wywołuje wskazany inicjator. Metoda klasy również tworzy "losowe" wartości dla tego inicjatora. Jeśli zrobię to, co moim zdaniem sugerujesz, będę musiał skopiować kod dla tych "losowych" wartości w nadpisanej klasie (+ randomPossession), a także nadpisać wyznaczony inicjator, aby wywołać nowy inicjator klasy BallGlove, który dodaj moje dodatkowe informacje iVar. Dlaczego nadpisuje się metodę klasową, którą zaproponowałem jako szkodliwą w sensie ogólnym? Czy nie można go porównać do inicjowania łańcuchów inicjalizujących? –

+0

Nie sądzę, że to zbyt brzydkie - to po prostu nie jest bardzo powszechny wzór. Samo pytanie jest tego dobrym wskaźnikiem. :) Jedną rzeczą, która jest nieco niejasna z podklasą, jest nazwa metody, a dobre nazywanie jest jedną z najlepszych rzeczy na temat celu-c. W twoim przypadku metoda + randomBallGlove może być lepsza niż przesłonięcie. – Eiko

+0

Sugerujesz, że zamiast tego tworzę metodę klasy o nazwie + randomBallGlove, która obejmuje implementację + randomPossession i pożądaną implementację niestandardową? Brzmi dobrze jak dla mnie. Co sugerujesz, aby + randomPossession nadal był dostępny dla podklas Posiadanie? zastąpić metodę i czy rzuca wyjątek kierując użycie + randomBallGlove? Czy jest to zazwyczaj normalny protokół takich wydarzeń?Wiem, że ten przykład może nie istnieć w rzeczywistości, po prostu się uczę i jestem ciekawy co do zaakceptowanej implementacji w przypadku, gdyby tak się stało. Dzięki za pomoc! –

1

Tak, dopuszczalne jest wykonanie takiej inicjalizacji. Tak właśnie jest w większości przypadków. To znaczy, to jest powód do dziedziczenia po super klasie. Chcesz rzeczy oprócz tego, co jest obecne w super klasie. Więc wstawiasz kod do tego, co jest specyficzne dla odziedziczonej klasy i powinno to być zrobione w ten sposób.

Myślę, że sposób zainicjowania obiektu BallGlove jest również czynnikiem decydującym o tym, jak zdefiniować dziedziczoną metodę. Pojawia się pytanie, czy wywołać init Possession, czy wywołać init BallGlove (Nie to, że tworzenie instancji klasy jest jedynym miejscem do zastosowania metody klasy). Sprowadza się to do logiki tworzenia twoich obiektów, tj. Jak dobrze opisujesz obiekt BallGlove - czy upewniasz się, że twoja metoda klasy opisuje je w sposób, który pasuje do kryteriów obiektu BallGlove i nie staje się obiektem generycznym Possession. Moja odpowiedź brzmi, że jeśli potrafisz to zaimplementować prawidłowo, to używanie równoległej linii metod klasowych jest dopuszczalne.

Ponadto, nie ma znaczenia, czy wracają typu Possession w super klasy, ponieważ id może wskazywać na obiekt dowolnego typu klasy

+0

Dzięki za odpowiedź. To jednak tak naprawdę nie odpowiadało na pytanie. Pytanie dotyczyło formatu nadpisujących metod klasowych. Pomijając konieczność wygenerowania metody wygodnej dla podklasy, nie jestem pewien, dlaczego nadpisałem metodę klasy. Jako takie, nie widziałem jeszcze nic na ten temat. Czy istnieją przykłady potwierdzające, że użyty format jest odpowiedni? –

+0

@BrianPalma Przykro mi. Być może nie odpowiedziałem poprawnie. Naprawdę nie widzę powodu, dla którego nie jest dopuszczalne robienie tego dla metod klasowych w taki sam sposób, jak inicjalizatorów. Sposób w jaki pracuję, to metody klasy mają tendencję do wywoływania metod init, wykonywania kodu i zwracania autoreleased wersji, która jest tym, co robisz. Nie wiem, czy istnieją przykłady weryfikacji formatu, ale nie widzę też żadnych problemów, które mogłyby z tego wyniknąć. Pozwól, że sprawdzę kilka przykładowych kodów i skontaktuję się z Tobą. – MadhavanRP

2

Tak, to doskonale rozsądny sposób to zrobić. Nie ma nic szczególnie odmiennego między metodami klasowymi i normalnymi metodami - tylko ta jest wykonywana przez klasę, a druga jest wykonywana przez instancję.

2

W momencie nadpisania metody klasy można zdecydować o jej wdrożeniu za pomocą superplikacji lub bez niego. To zależy od ciebie. Overiding init jest całkowicie odmienną historią, nie tylko dlatego, że jest metodą instancji, ale dlatego, że zawiera konwencję/kontrakt z nią związany. Należy pamiętać, że na przykład nie należy naruszać zasady Liskov Subtitution.

Twoje nadrzędne względem metody klasy jest doskonale, chociaż uważam za overiding klasy metod zapach projektu. Chociaż jest to bardzo możliwe w Objective-C, nie ma go w innych językach i to z bardzo dobrego powodu. Polimorfizm jako koncepcja lepiej wiąże się z przypadkami, które mogą być używane jako substytuty dla siebie nawzajem, podczas gdy użycie metod klasowych łamie koncepcję (tj. Brak rzeczywistej subtytucji).Jest sprytny, ale niekoniecznie intuicyjny i elastyczny.

+0

Dzięki za odpowiedź. Jak wspomniałem poniżej, nie jestem świadomy żadnego użycia nadpisania konkretnej metody klasy w podklasie, za wyjątkiem mniej kodu w metodzie wygody. W tym momencie nie mam zamiaru tego robić. Byłem tylko ciekawy co do właściwego wdrożenia, jeśli zaistniała sytuacja. –

+0

@BrianPalma: Istnieją powody do nadpisania metod klas innych niż "metody wygodne". Na przykład, metody NSView 'defaultMenu' i' requireConstraintBasedLayout' istnieją tylko po to, aby zostać zastąpione. – Chuck

+0

@Chuck Przepraszam, myślę, że źle napisałem lub jestem po prostu zbyt nowy! Mam na myśli "metody wygody" w kategoriach obiektów modelu. Rozumiem, że istnieją metody klasy w systemach iOS i OS X, które istnieją tylko w celu nadpisania i wymagają [super someClassMethodHere]; –

Powiązane problemy