我一直在寻找在Objective-C中实现Visitor设计模式的最佳方式.由于语言不支持方法重载,所以在
Java中可能发现的一个“传统”实现似乎是不可能的.
在我目前的实现中,我有一个Visitor协议,一个Visitor类和该Visitor类的几个子类,以及要访问的各种对象.一旦被访问的对象接受访问者,他们会调用访问者的访问方法,将其自身传递给参数.访问方法需要一个id,然后键入 – 转换它并调用
[self performTasksOnObjectClass: (ObjectClass *)object];
作为if / elseif / else块的一部分.这些调用由相关的访问者子类接收,访问者执行对象所需的任何任务.
有没有比这更好的方式来实现访客模式?我不喜欢使用’isKindOfClass’或’isMemberOfClass’调用if / elseif / else块.它看起来很笨拙,不雅.另外,以这种方式实施访问者方法仍然值得吗?被访问的对象仍然可以忽视访问者,但还有其他方法可以实现.
已经提出,代理或类集群可能更适合访问者模式的替代.我有兴趣看看你的想法!
解决方法
你可以使用一些内省/反思来使它更清洁一些.您不能重载方法名称,但您可以避免编写如下所示的switch语句:
- (void)performTasks:(id)object { Class class = [object class]; while (class && class != [NSObject class]) { NSString *methodName = [NSString stringWithFormat:@"perform%@Tasks:",class]; SEL selector = NSSelectorFromString(methodName); if ([self respondsToSelector:selector]) { [self performSelector:selector withObject:object]; return; } class = [class superclass]; } [NSException raise:@"Visitor %@ doesn't have a performTasks method for %@",[self class],[object class]]; }
您的实际performTasks方法将被命名如下:
- (void)performFooTasks:(Foo *)foo { //tasks for objects of class Foo } - (void)performBarTasks:(Bar *)bar { //tasks for objects of class Bar } etc...
注意:如果使用ARC,那么通过以这种方式从字符串创建选择器将会收到虚假的警告,因为它无法在编译时告诉方法参数的保留规则.您可以使用#pragma使这些警告静音,如下所示:
#pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [self performSelector:selector withObject:object]; #pragma clang diagnostic pop