#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. Тем не менее, спасибо за это!