Patterns / Behavioral patterns
image

@class EngineWheelCar;

//Visitor
//There is no overloading by parameter type in Objective-C:
//every visit has its own selector, and the element itself
//picks the right one in accept
@protocol CarVisitor <NSObject>
- (void)visitEngine:(Engine *)engine;
- (void)visitWheel:(Wheel *)wheel;
- (void)visitCar:(Car *)car;
@end

@protocol Element <NSObject>
- (void)accept:(id<CarVisitor>)v;
@end

//ConcreteElement
@interface Engine : NSObject <Element>
@end

@implementation Engine
- (void)accept:(id<CarVisitor>)v {
    [v visitEngine:self];
}
@end

//ConcreteElement
@interface Wheel : NSObject <Element>
@property (nonatomicreadonlyNSInteger number;

- (instancetype)initWithNumber:(NSInteger)number;
@end

@implementation Wheel

- (instancetype)initWithNumber:(NSInteger)number {
    self = [super init];
    if (self) {
        _number = number;
    }
    return self;
}

- (void)accept:(id<CarVisitor>)v {
    [v visitWheel:self];
}
@end

//ConcreteElement
@interface Car : NSObject <Element>
@property (nonatomic, strongreadonlyNSArray<id<Element>> *items;
@end

@implementation Car

- (instancetype)init {
    self = [super init];
    if (self) {
        _items = @[[[Engine allocinit],
                   [[Wheel alloc] initWithNumber:1],
                   [[Wheel alloc] initWithNumber:2],
                   [[Wheel alloc] initWithNumber:3],
                   [[Wheel alloc] initWithNumber:4]];
    }
    return self;
}

- (void)accept:(id<CarVisitor>)v {
    for (id<Element> e in self.items) {
        [e accept:v];
    }
    [v visitCar:self];
}
@end

//ConcreteVisitor
@interface TestCarVisitor : NSObject <CarVisitor>
@end

@implementation TestCarVisitor

- (void)visitEngine:(Engine *)engine {
    NSLog(@"test engine");
}

- (void)visitWheel:(Wheel *)wheel {
    NSLog(@"test wheel #%ld", (long)wheel.number);
}

- (void)visitCar:(Car *)car {
    NSLog(@"test car");
}
@end

//ConcreteVisitor
@interface RepairCarVisitor : NSObject <CarVisitor>
@end

@implementation RepairCarVisitor

- (void)visitEngine:(Engine *)engine {
    NSLog(@"repair engine");
}

- (void)visitWheel:(Wheel *)wheel {
    NSLog(@"repair wheel #%ld", (long)wheel.number);
}

- (void)visitCar:(Car *)car {
    NSLog(@"repair car");
}
@end

//Client
Car *car = [[Car allocinit];
TestCarVisitor *v1 = [[TestCarVisitor allocinit];
RepairCarVisitor *v2 = [[RepairCarVisitor allocinit];

[car accept:v1];
[car accept:v2];


Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.