Вы бы сказали, что категории Objective-C являются реализацией visitor design pattern?Объективные категории C == шаблон посетителя?
ответ
Нет, категории Objective-C не являются реализацией шаблона посетителя. Категории действительно не имеют точного соответствия в мире шаблонов проектирования, так как метод инжекции методов в существующие классы без подклассов невозможен на большинстве языков. Я бы сказал, что он ближе к decorator pattern, но этот шаблон обычно реализуется с композицией, то есть путем обертывания экземпляра объекта, который вы хотите «улучшить».
Шаблон посетителя полезен для инкапсуляции алгоритма алгоритма, который может применяться к множеству объектов, структур и т. Д. Например, если вы хотите создать вывод HTML для графика объектов, вы можете (A) написать htmlString
на каждом объекте и вызвать его для каждого объекта, или (B) использовать шаблон посетителя и создать конкретного посетителя, который знает, как создавать выходные данные HTML для каждого узла, который он посещает.
Бывший подход более общий, а логика задачи T разбросана по небольшим кускам по классам X, Y и Z. Последний подход помещает весь связанный код в один объект-посетитель, который имеет тенденцию упрощать обслуживание и предотвратить проблему «Я забыл об одном классе ...». Тем не менее, шаблон посетителя, возможно, несколько тяжелый для простых ситуаций, где он действительно окупается, - это когда у вас есть несколько различных параллельных функций и вы хотите отвлечь логику от классов, на которых выполняется функциональность. Например, вы можете внедрять других посетителей, которые производят вывод PDF или RTF и т. Д. Каждый посетитель может позаботиться о рекурсии и вызвать свои собственные методы посещения в нужном порядке, а отдельные посетители могут использовать совершенно отличный порядок.
Следует отметить, что на многих языках шаблон посетителя использует перегрузку метода (одно имя, другую подпись/аргументы). Поскольку Objective-C не разрешает перегрузку метода, вы должны использовать разные имена методов, но это может фактически помочь избежать ошибок, вызванных тем, что не зная, какая перегрузка вызывается.
Категории могут быть использованы для реализации шаблона посетителя.
@protocol Visit
- (void)acceptVisitor:(MyVisitor *)visitor;
@end
@interface Foo (Visit) <Visit>
@end
@interface Bar (Visit) <Visit>
@end
@implementation MyVisitor
- (void)visit:(id)someObject {
if ([someObject conformsToProtocol:@protocol(Visit)]) {
[(id<Visit>)someObject acceptVisitor:self];
}
}
- (void)visitFoo:(Foo *)foo { ... }
- (void)visitBar:(Bar *)bar { ... }
@end
@implementation Foo (Visit)
- (void)acceptVisitor:(MyVisitor *)visitor {
[visitor visitFoo:self];
}
@end
@implementation Bar (Visit)
- (void)acceptVisitor:(MyVisitor *)visitor {
[visitor visitBar:Self];
}
@end
Это IMO аккуратнее, чем классический дизайн GoF посетителей, так как нет никакого загрязнения открытых интерфейсов посещаемых классов, и все это может быть воплощено в единице компиляции класса посетителя.