Настройка подкласса Objective-C

У меня есть 3 класса Objective-C:

Animal - a subclass of NSObject
Feline - a subclass of Animal
Cat - subclass of Feline

Каждый из этих трех классов реализует (как я думал) свой собственный закрытый метод (-private_Setup) для настройки:

например в животных:

-(instancetype)init
{
    self = [super init];
    if (self) {
        [self private_Setup];
    }
    return self;
}

То же самое в классах Feline и Cat.

Список необходимых классов предоставляется во время выполнения, поэтому я создаю экземпляры различных классов в зависимости от списка имен классов.

e.g.

NSString *className = ... // @"Animal", @"Feline" or @"Cat".
id animal = [[NSClassFromString(className) alloc] init];

Проблема:

Если я создаю экземпляр Cat, -private_Setup вызывается несколько раз для каждого шага в цепочке наследования. Например, цепочка вызовов для Кота:

-[Cat init]
-[Feline init]
-[Animal init]
-[Cat private_Setup]    // First!

тогда из:

-[Feline init]
-[Cat private_Setup]    // Second!

тогда из:

-[Cat init]
-[Cat private_Setup]    // Third!

Таким образом, то, что я считал методом, приватным для каждого класса, вызывается после каждого -init в иерархии.

Может ли кто-нибудь посоветовать, как я могу решить эту проблему или изменить мои стратегии установки? Спасибо.

[отредактировано, добавлено для ясности]

На каждом уровне наследования требуется некоторая форма настройки для предоставления данных, специфичных для этого уровня. например Специальные настройки для кошек.

Таким образом, мне нужно, чтобы объект Cat был полностью настроен как Animal, как Feline и как Cat.

Я предполагаю, что один подход состоит в том, чтобы иметь разные имена методов настройки на каждом уровне. например setupAnimal, setupFeline, setupCat.

например в животных:

-(instancetype)init
{
    self = [super init];
    if (self) {
        [self setupAnimal];
    }
    return self;
}

// в кошачьем:

-(instancetype)init
{
    self = [super init];
    if (self) {
        [self setupFeline];
    }
    return self;
}

// в Коте:

-(instancetype)init
{
    self = [super init];
    if (self) {
        [self setupCat];
    }
    return self;
}

Есть ли лучший, более предпочтительный дизайн, чем этот?


person Womble    schedule 25.08.2014    source источник


Ответы (3)


Я думаю, что вы должны вызвать метод private_Setup только один раз - в Animal в init. Это все. Реализовать во всех подклассах, вызвать только один раз в supercalass

Вы говорите, что вам нужна разная форма установки для каждого подкласса. Конечно! Вот почему вы реализуете private_Setup в каждом подклассе. Реализуйте так, как вам нужно для каждого конкретного подкласса. Это называется переопределением. Внутри переопределенного вызова метода [super private_Setup]. Вы получите именно то, что вам нужно.

person Andrey Chernukha    schedule 25.08.2014

Вы говорите super init, а супермен init звонит private_Setup, так чему вы удивляетесь?

Думаю, вы удивлены, потому что ожидаете, что каждый init в цепочке вызовет private_Setup своего собственного класса. Но нужно понимать, что значение self меняется в зависимости от исходного класса экземпляра, запустившего цепочку (полиморфизм).

Так, например, если вы вызываете self private_Setup из init животного во время процесса инициализации Cat, будет вызываться Cat private_Setup. Таким образом, с учетом того, что вы сделали, совершенно верно, что при инициализации Cat private_Setup Cat будет вызываться три раза, и ни один из других не будет вызываться.

Решение простое: не используйте дополнительный метод. Это большая ошибка, когда инициализатор вызывает любые методы (и проблема, с которой вы столкнулись, является одной из причин этой ошибки). Вместо этого просто выполните настройку в самом init. Вот для чего это нужно.

person matt    schedule 25.08.2014

Если я правильно понимаю, вы подразумеваете, что вызов private_Setup происходит и во всех методах инициализации ваших подклассов.

Удалите вызов private_Setup из всех методов инициализации, кроме верхнего (например, Animal). Пока все они вызывают [super init], вы получите ровно один вызов private_Setup.

person Chris Trahey    schedule 25.08.2014