AbstractFactory шаблон в цель-с
Я просто пытаюсь выучить цели.
Я видел пример из Википедии для шаблона AbstractFactory на разных языках.
Вот определение кнопки:
@protocol Button
- (void)paint;
@end
@interface WinButton : NSObject <Button>
@end
Вот фабрика:
@implementation WinFactory
- (id)createButton {
return [[[WinButton alloc] init] autorelease];
}
@end
Насколько я знаю, obj-c id
Ключевое слово должно быть что-то вроде C# var
или C++11 auto
, право?
Итак, мой вопрос:
зачем фабрике возвращать универсальный объект не указанного типа? Это ошибка (которая позволяет фабрике возвращать что-то другое, не являющееся кнопкой) или есть причина для этого?
Я бы написал фабрику так:
@implementation WinFactory
- (id<Button>)createButton {
return [[[WinButton alloc] init] autorelease];
}
@end
я ошибся?
3 ответа
зачем фабрике возвращать универсальный объект не указанного типа?
Во многих случаях, когда вы видите id
возвращено, это потому, что они не являются последовательно типизированными (действительно абстрактными объектами), или это потому, что неявный upcast был бы введен.
Это ошибка (которая позволяет фабрике возвращать что-то другое, не являющееся кнопкой) или есть причина для этого?
Это не ошибка. Конечно, вы не должны возвращать тип, который не соответствует.
Я бы написал фабрику так:… я не прав?
@implementation WinFactory
- (id<Button>)createButton {
return [[[WinButton alloc] init] autorelease];
}
@end
Главное в этом сценарии заключается в том, что ObjC довольно свободно напечатан, и вы должны стремиться к тому, чтобы параметры всех селекторов и типы возвращаемых данных совпадали. То есть каждый createButton
во всех ваших переводах все должны возвращать один и тот же тип и иметь одинаковые типы для параметров. Иногда вам придется выбирать более описательное имя, чтобы избежать неоднозначности для компилятора.
Это должно объяснить, почему +[NSString string]
возвращается id
- если он вернулся NSString
, затем +[NSMutableString string]
может быть источником предупреждений. Это связано с тем, что компилятору может быть трудно (невозможно) сопоставить объявление метода с динамическим экземпляром. Это также может помочь вам понять "многословное" наименование селекторов, таких как удобные конструкторы, которые также содержат тип в методе (например, +[NSDictionary dictionaryWithObject:]
в отличие от просто +[NSDictionary withObject:]
).
Но чтобы перейти к вашему вопросу: id<Button>
или же NSObject<Button>*
или какой-то другой квалифицированный тип - это нормально, если вы можете жить с этой общей сигнатурой метода. Вы вводите тип-квалификацию, которая помогает компилятору помочь вам.
Более правильный тип возврата здесь будет:
- (id<Button>)createButton;
Это означает, что возвращаемый тип является объектом, который соответствует <Button>
протокол. Я могу исправить страницу WP, чтобы быть немного более понятным. <Button>
Протокол также должен наследоваться от <NSObject>
протокол для полноты (и для упрощения фактического использования).
Обратите внимание, что шаблон Абстрактной Фабрики несколько необычен в ObjC. Я пытаюсь придумать случай, когда он используется в UIKit или Foundation. Для класса более характерно обрабатывать это внутренне (например, в NSNumber
) и называется кластером классов.
Будьте очень осторожны при попытке написания кода в стиле C++ или C# в ObjC. ObjC не является статическим языком, и используемые шаблоны часто совершенно разные. (Я не говорю, что AF - это статический паттерн. Он может быть достаточно хорошо использован в ObjC. Я просто говорю, что тот факт, что вы смотрите на него, пытаясь изучить ObjC, означает, что вы можете подойти к нему задом наперед. изучая "как мне сделать этот C++ в ObjC", а не "как мне развиваться в ObjC".)
Objective-C имеет концепцию кластеров классов, которые являются абстрактными фабриками. Смотрите этот ответ.