2013-06-17 14 views
6

Chciałbym dziedziczyć z klasy szkieletowej, która ma metodę fabryczną. Jak mogę uczynić metodę factory zwrócić obiekt mojego odziedziczonego typu klasy? Znalazłem this useful article, które opisują podobną sytuację, ale w ich przypadku masz kontrolę nad nadklasą. Jak napisać, powiedzmy, podklasę UIImage, która zwróci obiekt mojego podklasy?Dziedziczenie klasy C z metodami fabrycznymi

+2

może możesz osiągnąć to, co chcesz, pisząc kategorię na UIImage? –

+0

Tak, teraz myślę o tym kierunku. Tyle tylko, że potrzebuję dodatkowych członków klasy (właściwości) i chciałem uniknąć kłopotów z objc_setAssociatedObject i przyjaciółmi. Również dlatego, że nie uważam za eleganckie stworzenie obejścia tego typu dla zupełnie innego problemu. Jednak obawiam się coraz bardziej, że nie mam wyboru. – MrTJ

+1

spójrz na kategorię [NSObject] (https://github.com/pixelflut/PixLib-OpenSource/blob/master/PixLib%20OpenSource/NSObject%2BPixLib.m). Dwie metody "setRuntimeProperty: name:" i "runtimeProperty:" pomagają w ustawieniu i dostępie do powiązanych obiektów. –

Odpowiedz

9

Chciałbym dziedziczyć z klasy szkieletowej, która ma metodę fabryki. Jak mogę uczynić metodę factory zwrócić obiekt mojego odziedziczonego typu klasy?

To wszystko co powinny zrobić:

@interface MONImage : UIImage 
@end 

@implementation MONImage 
@end 

Następnie:

MONImage * image = [MONImage imageNamed:name]; 

Jak mogę napisać, powiedzmy, podklasy UIImage że imageNamed: zwrócił obiekt typu mojej podklasy?

Implementacja

+[UIImage imageNamed:] napisała podkategorizerów z tego podejścia. W związku z tym musisz sam wdrożyć tę metodę.

Oto jak jeden powinny zadeklarować metody fabryki:

+ (instancetype)imageNamed:(NSString *)pName; 

i jak jeden powinny wdrożyć go:

+ (instancetype)imageNamed:(NSString *)pName 
{ 
    MONImage * image = [[self alloc] initWithThisDesignatedInitializer:pName]; 
         ^^^^ NOTE: self, not a concrete class 
    ...set up image... 
    return image; 
} 

ale nie zrobili to w ten sposób - +[UIImage imageNamed:] napisał podklasa i zwraca UIImage podczas pisania MONImage * img = [MONImage imageNamed:pName];. Czasami robi się to z dobrego powodu. Niektóre metody powinny mieć "ostateczną" semantykę. Często pojawia się, gdy twoja metoda może zwrócić wiele typów, tak jak w klastrze klasy. Język nie wyraża "ostatecznych" metod - ale taka metoda powinna być przynajmniej udokumentowana.


więc podjechać do tego UIImage przypadku:

@interface MONImage : UIImage 

+ (instancetype)imageNamed:(NSString *)pName; 

@end 

@implementation MONImage 

+ (instancetype)imageNamed:(NSString *)pName 
{ 
    UIImage * source = [UIImage imageNamed:pName]; 
    CGImageRef cgImage = source.CGImage; 
    if (cgImage) 
     return [[self alloc] initWithCGImage:cgImage]; 
    // try it another way 
    return nil; 
} 

@end 

Zauważ, że UIImage s i CGImage s są niezmienne. Nie powinno to skutkować głęboką kopią danych obrazu.

+2

+1 za korzystanie z typu instancetype. – Abizern

+2

czy to również zapewnia zachowanie buforowania '[UIImage imageNamed:]'? Jeśli nie, być może powinieneś zapisać odniesienie do oryginalnego obrazu w 'MONImage'. Ale naprawdę fajne rozwiązanie. –

+0

@ JonathanCichon zachowałoby zachowanie wyszukiwania '+ imageNamed:'. ładowałby obraz, a następnie buforował go. dokładne zachowanie implementacji buforowania jest wyabstrahowane, więc mój wniosek jest taki, że nie gwarantuje się identyczności pod tym względem. Przypuszczam, że * to samo dotyczy buforowania, ale tego nie udowodniłem. dobre pytanie. – justin

2

Dla przykładu:

  • Podklasa UIImage do, powiedzmy, MyImage
  • Wdrożenie metody imageNamed: na nic konkretnego, które muszą być wykonane.
  • wywołanie tej metody w tej klasie: MyImage *newImage = [MyImage imageNamed:imageName];
+2

To naprawdę nie pomoże, ponieważ nie można nazwać 'super' we własnej implementacji' imageNamed', ponieważ spowoduje to zwrócenie instancji typu 'UIImage'. –

+0

Kto powiedział, że musi zadzwonić super? może przydzielić i zainicjować obiekt swojej podklasy w metodzie i zwrócić to. I, jak wszyscy wiemy, konwencja jest dla podklas, aby wywoływać swój inicjator wyznaczonej superklasy, która zwraca obiekt typu "id". W każdym razie jest to wymyślny przykład oparty na tym, o co prosił OP. Szczegóły pozostawia się użytkownikowi, ale zasadą konstruktora wygody przydzielającego i inicjującego obiekt jego własnej klasy jest dźwięk. – Abizern

+1

tak, ale w tym przypadku "magiczne" jabłko robi w "imageNamed:' jest bardzo użyteczne i nie sądzę, że chce to wdrożyć samodzielnie. Ale masz rację, twoja odpowiedź nie jest "zła", ale myślę, że nie jest bardzo przydatna w TEN przypadku. –

0

Podejście to rozwiązać mój problem był w użyciu kategorię zamiast dziedziczenia (kredyty przejść do Jonathan Cichon w komentarzach moje pytanie). Użyłem Associative References do zadeklarowania i przechowywania dodatkowych danych w implementacji kategorii, jak to omówiono tutaj w SO. Chciałbym zwrócić uwagę na zaproponowany przez Jonathana model NSObject category implementation, który sprawia, że ​​dodawanie odwołań asocjacyjnych do dowolnego obiektu jest naprawdę łatwe i eleganckie.

+0

Podczas gdy cieszę się, że rozwiązałeś swój problem - twoje pytanie dotyczyło nadpisywania konstruktorów wygody, które następnie zmieniłeś na pytanie o dodanie pamięci do klasy poza rozszerzeniem klasy. Tak naprawdę są dwa zestawy pytań i odpowiedzi w tym samym czasie. – Abizern

+0

Potrzebowałem rozszerzyć oryginalną klasę szkieletową o dodatkowe dane i nadal móc korzystać z jej oryginalnych konstruktorów wygody. Kiedy zadałem oryginalne pytanie, nie miałem pojęcia, jak to zrobić i przypuszczałem, że można to osiągnąć dzięki dziedziczeniu. Masz rację z punktu widzenia, że ​​nie określiłem dokładnie, że muszę dodać dodatkowe dane do klasy, ale napisał "dziedziczenie". Z drugiej strony rozwiązanie Jonathana doskonale rozwiązuje mój problem, nawet jeśli nie korzystam z dziedziczenia. – MrTJ

+0

UWAGA: Nie zmieniłem pierwotnego pytania i dodałem podpowiedź assoc.refs w tej odpowiedzi, tylko jako punkt odniesienia dla przyszłych czytelników. – MrTJ