Поставщик данных вызывает делегата: специфика или общая? - PullRequest
3 голосов
/ 26 июля 2011

У меня есть анализатор XML, который будет анализировать 17 различных документов XML (я упрощаю это).Когда анализатор завершил свою работу, он вызывает объект, который выполнил запрос.

Первый способ

Единственный метод, который выглядит как

- (void)didReceiveObject:(NSObject *)object ofType:(MyObjectType)type

с MyObjectType, являющимся перечислением.

В этом методе я проверяю тип и перенаправляю объект в соответствующий метод.

Второй способ

Для каждого метода существует метод обратного вызоваиз 17 типов объектов, которые я могу получить.

- (void)didReceiveFoo:(MYFoo *)foo
- (void)didReceiveBar:(MYBar *)bar
... and so on

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

Даже когда мы думаем о добавлении обратных вызовов методов / делегатов, мы не видим реальной проблемы.

Один из этих способов лучше, чем другой?Есть ли другой способ?

Ответы [ 3 ]

2 голосов
/ 03 августа 2011

Почему бы не пойти с

- (void)didReceiveObject:(NSObject *)object

, а затем проверить тип класса?

Это кажется мне более понятным и расширяемым, потому что это означает, что вы можете анализировать другие объекты в будущем без добавления дополнительных обратных вызовов.

(я знаю, что это то же самое, что и первый вариант, нохотел бы отметить, что ваш второй аргумент не нужен.)

1 голос
/ 03 августа 2011

Первый метод:

Плюсы:

  • Более гибкие возможности для будущих изменений.

Минусы:

  • Может привести к большому оператору switch или к грязному оператору if ... else if ... else.
  • Вероятно, в любом случае приводит к серии явных методов.
  • Требуется тип приведения.

Второй метод:

Плюсы:

  • Нет типа приведения.
  • Если методы являются необязательными, делегат беспокоит только те объекты, которые его интересуют.

Минусы:

  • Если методы не являются обязательными и интерфейспозже, все делегаты будут получать предупреждения, пока не будут реализованы новые методы.
  • Если методы не являются обязательными, это может быть множество методов, которые можно реализовать для каждого делегата.

Обычно при создании интерфейсов делегатов я склоняюсь к обобщениям для будущей расширяемости.Изменение API, особенно с открытым исходным кодом, может быть очень сложным.Кроме того, я не совсем понимаю, почему у вас один XML-парсер делает так много.Вы можете рассмотреть другой дизайн.17 различных XML-документов кажутся много.Помимо этого, я предложу третий метод.

Третий метод:

Создать словарь, который отображает строки в блоки.Блоки, вероятно, будут иметь тип void(^BlockName)(id obj).Ваш парсер определит серию строк, которые будут ключами для ваших различных блоков.Например,

NSString * const kFooKey = @"FooKey"; 
NSString * const kBarKey = @"BarKey";
// And so on...

Кто бы ни создавал синтаксический анализатор XML, он регистрирует блок для каждого ключа, который их интересует. Он должен регистрироваться только для ключей, которые его интересуют, и он полностью гибок для будущих изменений.Поскольку вы регистрируетесь для явных ключей / объектов, вы можете подтвердить переданный тип без приведения типа (по существу Design By Contract ).Это может быть слишком сложно для того, что вы хотите, но я нашел подобные проекты очень полезными в моем коде.Он сочетает в себе плюсы обоих ваших решений.Это основной недостаток, если вы хотите использовать SDK, который не имеет блоков.Тем не менее, блоки становятся де-факто стандартом с Objective-C.

Кроме того, вы можете определить протокол, который включает в себя общие функциональные возможности ваших 17 объектов, если вы еще этого не сделали.Это изменит тип вашего блока на void(^BlockName)(id<YourProtocol> obj).

0 голосов
/ 03 августа 2011

Вот решение.

Мы реализуем оба варианта и посмотрим, какой из них используется чаще.

Первый способ самый простой и быстрый, поэтому мы сохраним его для внутренних нужд.

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

Поскольку для каждого обратного вызова должен быть большой кусок кода, универсальным способом, безусловно, будет большой оператор switch, указанный rbrown.

Спасибо за вашу помощь.

...