Создание экземпляра подкласса из материнского класса разумно

#ios #objective-c #class #inheritance #initialization

#iOS #objective-c #класс #наследование #инициализация

Вопрос:

Допустим, у меня есть материнский класс (абстрактный или нет) Item и два подкласса ItemA и itemB, которые оба наследуются от Item

Все экземпляры создаются на основе NSDictionary с помощью следующего метода

 -(id)initWithJSON:(NSDictionary *)d{

//first instantiate common properties from the motherclass
    if ([super initWithJSON:d]){
        //Do specific stuff for the subclass
    }
    return self;
}
 

Теперь предположим, что я извлекаю из веб-сервиса массив, который может содержать как ItemA, так и Item для создания.

В настоящее время я использую условие if / then, чтобы определить, какой подкласс я буду создавать, например, на основе содержимого словаря :

  [(NSArray*)data enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

            if ([obj[@"kind"] isEqualToString:@"A"])
                [interactions addObject:[[ItemA alloc] initWithJSON:obj]];
            else if ([obj[@"kind"] isEqualToString:@"B"])
                [interactions addObject:[[ItemB alloc] initWithJSON:obj]];
            else
            [interactions addObject:[[Item alloc] initWithJSON:obj]];

        }];
 

Теперь моя точка зрения заключается в следующем: есть ли способ иметь только одну строку кода, которая будет — по умолчанию — создавать экземпляр объекта Item и на основе вида ItemA или itemB
Другими словами, могу ли я написать некоторый код в методе init элемента motherclass для создания экземпляра подкласса вместо этого, если выполняются некоторые условия в параметрах NSDictionary, которые анализируются?

Спасибо

Комментарии:

1. A и B всегда являются Item , поэтому просто вызывайте его и игнорируйте, являются ли они A или B.

2. @MarcoAcierno Я этого не понимаю

Ответ №1:

в вашем материнском классе добавьте удобный метод, подобный этому:

   (instancetype)itemWithJSON:(NSDictionary *)obj {
        id item; 

        if ([obj[@"kind"] isEqualToString:@"A"]) {
            item = [[ItemA alloc] initWithJSON:obj];
        } else if ([obj[@"kind"] isEqualToString:@"B"]) { 
            item = [[ItemB alloc] initWithJSON:obj];
        } else {
            item = [[Item alloc] initWithJSON:obj];
        }

        return item;
 }
 

затем используйте его следующим образом:

  [(NSArray*)data enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
     [interactions addObject:[Item itemWithJSON:obj]];
 }];
 

Комментарии:

1. это инкапсулирует логику, какой тип элемента инициализировать / или даже КАК его инициализировать, внутри этой удобной функции!

2. Кажется, это хороший и правильный способ сделать это, спасибо. Думал об этом, но в основном хотел проверить, есть ли другие рекомендации. Большое спасибо!

Ответ №2:

Взгляните на NSClassFromString .

Пример псевдокода:

 NSString *className = [NSString stringWithFormat:@"Item%@", obj[@"kind]];
Class metaClass = NSClassFromString(className);

*instance = [[metaClass alloc] initWithJSON:obj];
 

Затем вы инкапсулируете это поведение в статический фабричный метод класса в свой материнский класс. Подробности см. В Ответе Daij-Djan.

Комментарии:

1. Спасибо, я уже делал это в прошлом, что работает и действительно удобно. На этот раз соглашение об именовании различных подклассов не настолько близко к соглашению о материнском классе, что подразумевает добавление логики if / then. Тем не менее, спасибо за это!