2009-08-26 2 views

ответ

11

Нет, категории Objective-C не являются реализацией шаблона посетителя. Категории действительно не имеют точного соответствия в мире шаблонов проектирования, так как метод инжекции методов в существующие классы без подклассов невозможен на большинстве языков. Я бы сказал, что он ближе к decorator pattern, но этот шаблон обычно реализуется с композицией, то есть путем обертывания экземпляра объекта, который вы хотите «улучшить».

Шаблон посетителя полезен для инкапсуляции алгоритма алгоритма, который может применяться к множеству объектов, структур и т. Д. Например, если вы хотите создать вывод HTML для графика объектов, вы можете (A) написать htmlString на каждом объекте и вызвать его для каждого объекта, или (B) использовать шаблон посетителя и создать конкретного посетителя, который знает, как создавать выходные данные HTML для каждого узла, который он посещает.

Бывший подход более общий, а логика задачи T разбросана по небольшим кускам по классам X, Y и Z. Последний подход помещает весь связанный код в один объект-посетитель, который имеет тенденцию упрощать обслуживание и предотвратить проблему «Я забыл об одном классе ...». Тем не менее, шаблон посетителя, возможно, несколько тяжелый для простых ситуаций, где он действительно окупается, - это когда у вас есть несколько различных параллельных функций и вы хотите отвлечь логику от классов, на которых выполняется функциональность. Например, вы можете внедрять других посетителей, которые производят вывод PDF или RTF и т. Д. Каждый посетитель может позаботиться о рекурсии и вызвать свои собственные методы посещения в нужном порядке, а отдельные посетители могут использовать совершенно отличный порядок.

Следует отметить, что на многих языках шаблон посетителя использует перегрузку метода (одно имя, другую подпись/аргументы). Поскольку Objective-C не разрешает перегрузку метода, вы должны использовать разные имена методов, но это может фактически помочь избежать ошибок, вызванных тем, что не зная, какая перегрузка вызывается.

2

Категории могут быть использованы для реализации шаблона посетителя.

@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 посетителей, так как нет никакого загрязнения открытых интерфейсов посещаемых классов, и все это может быть воплощено в единице компиляции класса посетителя.