I've been looking at the best way to implement the Visitor design pattern in Objective-C. Since the language doesn't support method overloading, a 'traditional' implementation such as one might find in Java seems impossible.
In my current implementation, I have a Visitor protocol, a Visitor class, and several subclasses of that Visitor class, along with the various objects to visit. Once a visited object accepts the Visitor, they call the visit method of the Visitor, passing themselves as an argument. The visit method takes an id, then type-casts it and calls
[self performTasksOnObjectClass: (ObjectClass *)object];
as part of an if/elseif/else block. These calls are them picked up by the relevant Visitor subclass and the Visitor performs whatever tasks it needs to on the object.
Is there a better way of implementing the Visitor pattern than this? I dislike resorting to 'isKindOfClass' or 'isMemberOfClass' calls inside if/elseif/else blocks. It just seems clunky and inelegant. Additionally, is it still 'worth' implementing a Visitor method in this way? The visited objects can still remain ignorant of the Visitor, but there are other ways in which this can be achieved.
It has already been suggested that either delegation or class clusters might be more suitable alternatives to the Visitor pattern. I'd be interested to see what you all think!
Edit: I actually had differently named methods being called in the subclass, I've made this clearer.
The purpose of a Visitor pattern is to define a new operation without introducing the modifications to an existing object structure. Imagine that we have a composite object which consists of components.
Visitor in C++ Visitor is a behavioral design pattern that allows adding new behaviors to existing class hierarchy without altering any existing code.
There are 23 types of design pattern in Java that provides the well-defined solutions to the commonly occurring problem in application design.
You can use some introspection/reflection to make this a bit cleaner. You can't overload method names but you can avoid writing a switch statement like this:
- (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]];
}
Your actual performTasks methods would then be named as follows:
- (void)performFooTasks:(Foo *)foo
{
//tasks for objects of class Foo
}
- (void)performBarTasks:(Bar *)bar
{
//tasks for objects of class Bar
}
etc...
Note: If you're using ARC, you'll get spurious warnings by creating selectors from strings in this way because it can't tell at compile time what the retain rules should be for the method parameters. You can silence these warnings using a #pragma, as follows:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self performSelector:selector withObject:object];
#pragma clang diagnostic pop
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With