Inicializace třídu pomocí rodičovské inicializátor

hlasů
7

Mám dvě třídy, jeden podtřídou jiné (řekněme Animala Dog). Nadtřídou má nějaké inicializátory (řekněme initAnimal), podtřída má několik inicializátory (řekněme initDog). Problém je v tom, že je perfektně legální (z pohledu kompilátoru) udělat něco podobného Dog *adog = [[Dog alloc] initAnimal], tzn. inicializovat třídu pomocí jeho nadřazené inicializátor. Nelíbí se mi to, protože podtřídy může mít nějaké další proměnné instance, které chci, aby se ujistil se inicializuje. Pohled do záhlaví souboru tento problém řeší, ale existuje jednoduchý způsob, jak šek kompilátor pro mě? Mám takový pocit jsem něco chybí strašně zřejmé, ale já prostě nemůžu si vzpomenout na to :-)

Aktualizovat:initDog a initAnimalnebyli nejlepší příklady. Měl jsem na mysli dva opravdu různé inicializátory (jako initu Animali initWithFurpro Dog). Kdybych chtěl každý pes, že některé fur přiděleno, udělal bych kožešinou část inicializátor, takže nikdo nemohl získat objekt pes bez srsti. Ale pak je to pořád snadné mylně inicializovat instanci s rodičovské třídy init, a pak jsem hosed.

Díky za vychovávat určené inicializátory, Jasone. To nebylo dříve, než dojde ke mně, ale já jsem mohl přetížit určený inicializátor z rodičovské třídy a nastavit některé rozumných výchozí tam. Ale já bych ještě raději, kdybych mohl nějak dělat to nezákonný používat jiné inicializátory než samotné třídy - žádné další nápady?

Položena 10/11/2008 v 10:59
zdroj uživatelem
V jiných jazycích...                            


1 odpovědí

hlasů
18

Obecně v Objective-C vytvořit určený inicializátor pro každou třídu a potom podtřídy používají stejný inicializátor. Takže namísto použití initAnimal a initDog, stačí použít init. Pes podtřídy by pak definovat svou vlastní metodu init a volat určený inicializátor ve své nadřazené třídy:

@implementation Dog
-(id)init
{
    if( (self = [super init]) ) {  // call init in Animal and assign to self
        // do something specific to a dog
    }
    return self;
}
@end

Nemáte opravdu nutné zadat initDog a initAnimal protože třída je deklarována na pravé straně přiřazení ...

Aktualizace: Já přidáním následující odpovědi tak, aby odrážely dodatečné informace v otázce

Existuje celá řada způsobů, jak zajistit, aby podtřídy nevolají jiné než jejich určeným inicializátor a jak si nakonec vyberete, bude z velké části založen na celém svém návrhu inicializátory. Jedním z pěkných věcí o Objective-C je, že je tak flexibilní. Uvedu dva příklady zde, které vám pomohou začít.

Za prvé, pokud si vytvořit podtřídu, která má jinou určenou inicializátor než své mateřské třídy, můžete přetížit rodiče inicializátor a vyvoláním výjimky. To umožní programátorům ihned vědí, že jsem porušil protokol pro svou třídu ... ale to by mělo být uvedeno, že byste měli mít velmi dobrý důvod, proč dělá to, a že by měl být velmi dobře zdokumentováno, že podtřídy nesmí používat stejně jako inicializátor rodičovské třídy.

@implementation Dog
-(id)init
{
    // Dog does not respond to this initializer
    NSAssert( false, @"Dog classes must use one of the designated initializers; see the documentation for more information." );

    [self autorelease];
    return nil;
}

-(id)initWithFur:(FurOptionsType)furOptions
{
    if( (self = [super init]) ) {
        // do stuff and set up the fur based on the options
    }
    return self;
}
@end

Dalším způsobem, jak to udělat, je mít inicializátor spíš původní příklad. V takovém případě byste mohli změnit výchozí init na nadřazené třídy, aby se vždy nezdaří. Dalo by se pak vytvořit vlastní inicializátor pro nadřazené třídy a pak se ujistěte se, že všichni říkají vhodný inicializátor do podtřídy. Tento případ je samozřejmě složitější:

@interface Animal : NSObject
-(id)initAnimal;
@end

@interface Animal ()
-(id)_prvInitAnimal;
@end

@interface Dog : Animal
-(id)initDog;
@end

@implementation Animal
-(id)init
{
    NSAssert( false, @"Objects must call designated initializers; see documentation for details." );

    [self autorelease];
    return nil;
}

-(id)initAnimal
{
    NSAssert( [self isMemberOfClass:[Animal class]], @"Only Animal may call initAnimal" );

    // core animal initialization done in private initializer
    return [self _prvInitAnimal];
}

-(id)_prvInitAnimal
{
    if( (self = [super init]) ) {
        // do standard animal initialization
    }
    return self;
}
@end

@implementation Dog
-(id)initDog
{
    if( (self = [super _prvInitAnimal]) ) {
        // do some dog related stuff
    }
    return self;
}
@end

Zde vidíte rozhraní a implementaci třídy zvířat a pes. Zvíře je určený objekt nejvyšší úrovně, a proto má přednost realizaci NSObject tohoto init. Každý, kdo volá init na zvířeti nebo na kteroukoli podtřídy zvířete dostanou chybu výrazu jejich předávání dokumentace. Animal také definuje vlastní inicializátor na vlastní kategorii. Soukromý kategorie by zůstat se svým kódem a podtřídy Animal by vyžadovalo tento soukromý inicializátor když volají do výborný. Jeho smyslem je volání init na zvířete nadtřídě (NSObject v tomto případě) a dělat nějakou generickou inicializace, které by mohly být nezbytné.

Konečně, první řádek v metodě initAnimal zvířete, je tvrzení, že přijímač je vlastně zvířat a ne nějaký podtřídy. V případě, že přijímač není Animal program selže s chybou tvrzení a programátor bude odkázán na dokumentaci.

To jsou jen dva příkladem toho, jak byste mohli vytvořit něco s vašim specifickým požadavkům. Nicméně bych důrazně doporučujeme, abyste zvážili své konstrukční omezení a zjistit, jestli je to opravdu nutné tento typ konstrukce, jak je to nestandardní v Cocoa a ve většině OO designu rámců. Například, můžete zvážit různých zvířat objekty kořenové úrovni a jen mít protokol Animal místo, vyžadující, aby všechny různé „zvířata“ reagovat na určité zprávy na zvířatech-generic. Tak každé zvíře (pravý a podtřídy Animal) zvládne svých určených Inicializátory sebe a nebude muset spoléhat na supertříd chovají v rámci takového zvláštního, nestandardním způsobem.

Odpovězeno 10/11/2008 v 11:07
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more