一个简单的Car模型,含有1台Engine、4个Wheel,使用访问者模式添加对Car的升级与维修操作。
定义Engine类:
// // NimoEngine.h // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import <Foundation/Foundation.h> #import "NimoComponentVisitor.h" @interface NimoEngine : NSObject @property (nonatomic, copy) NSString *modelName; - (id)initWithModelName:(NSString *)modelName; @end
// // NimoEngine.m // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import "NimoEngine.h" @implementation NimoEngine - (id)initWithModelName:(NSString *)modelName { self = [super init]; if (self) { _modelName = [modelName copy]; } return self; } - (id) init { return [self initWithModelName:@"Slant 6"]; } - (NSString *)description { return [NSString stringWithFormat:@"Engine: %@", _modelName]; } @end
定义Wheel类:
// // NimoWheel.h // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import <Foundation/Foundation.h> @interface NimoWheel : NSObject @property (nonatomic, assign) float diameter; //车轮直径 @end
// // NimoWheel.m // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import "NimoWheel.h" @implementation NimoWheel - (id)init { self = [super init]; if (self) { _diameter = 400.0f; } return self; } -(NSString *)description { return [NSString stringWithFormat:@"Wheel: %f mm", _diameter]; } @end
定义Car类:
// // NimoCar.h // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import <Foundation/Foundation.h> @class NimoEngine, NimoWheel; @interface NimoCar : NSObject @property (nonatomic) NimoEngine *engine; @property (nonatomic, readonly) NSArray *arrayOfWheels; - (void)addWheel:(NimoWheel *)wheel atIndex:(NSUInteger) index; @end
// // NimoCar.m // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // @interface NimoCar() @property (nonatomic, readwrite) NSMutableArray *mutableArrayOfWheels; @end @implementation NimoCar - (id)init { if (self = [super init]) { _mutableArrayOfWheels = [[NSMutableArray alloc] initWithCapacity:4]; } return self; } - (void)addWheel:(NimoWheel *)wheel atIndex:(NSUInteger) index { [_mutableArrayOfWheels insertObject:wheel atIndex:index]; } - (NSArray *)arrayOfWheels { return [_mutableArrayOfWheels copy]; } - (NSString *)description { return [NSString stringWithFormat:@"My car: %@", [NSDictionary dictionaryWithObjects:@[_engine, self.arrayOfWheels] forKeys:@[@"Engine", @"Wheels"]]]; } @end
我们的汽车结构很简单,只包含1个引擎,4个车轮,并且各个类也没有复杂的实现,仅仅覆写了description,让其输出简要的信息。
好,实例化一辆Car, 看看效果:
// // main.m // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import <Foundation/Foundation.h> #import "NimoCar.h" #import "NimoEngine.h" #import "NimoWheel.h" int main(int argc, const char * argv[]) { @autoreleasepool { NimoCar *car = [[NimoCar alloc] init]; NimoEngine *engine = [[NimoEngine alloc] initWithBrandName:@"V8"]; NimoWheel *wheelA = [[NimoWheel alloc] init]; NimoWheel *wheelB = [[NimoWheel alloc] init]; NimoWheel *wheelC = [[NimoWheel alloc] init]; NimoWheel *wheelD = [[NimoWheel alloc] init]; car.engine = engine; [car addWheel:wheelA atIndex:0]; [car addWheel:wheelB atIndex:1]; [car addWheel:wheelC atIndex:2]; [car addWheel:wheelD atIndex:3]; NSLog(@"%@", car); } return 0; }
控制台跟意料中一样输出了Car的信息。至此,准备工作做好了。
访问者模式:表示一个作用于某对象结构中的各元素的操作。它让我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。---《设计模式》(Addison-Wesley, 1994)
这段话比较拗口,不太好理解。拿刚刚完成的Car类来举例,NimoCar类就是对象结构,其中包含的元素为:NimoEngine类和NimoWheel类。如果现在需要对Car进行全面升级(新操作),通常的做法是NimoEngine与NimoWheel都向外提供“升级”的接口。如果还需要对Car进行维修呢?那又得向外提供“维修”的接口。随着类似的需求越多,NimoEngine与NimoWheel向外提供的接口就越多,类也变得越复杂。有没有简单的方法呢?有!把这些琐事都交给访问者来做吧,NimoEngine与NimoWheel只要同意被访问就成。
定义访问者协议:
// // ComponentVisitor.h // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // @class NimoEngine, NimoWheel; @protocol NimoComponentVisitor <NSObject> - (void) visitEngine:(NimoEngine *) engine; - (void) visitWheel:(NimoWheel *) wheel; @end
修改我们的类,使其能够接受访问
添加访问支持的Engine类:
// // NimoEngine.h // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import <Foundation/Foundation.h> #import "NimoComponentVisitor.h" @interface NimoEngine : NSObject @property (nonatomic, copy) NSString *modelName; - (id)initWithModelName:(NSString *)modelName; - (void)acceptComponentVisitor:(id<NimoComponentVisitor>) visitor; @end
// // NimoEngine.m // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import "NimoEngine.h" @implementation NimoEngine - (id)initWithModelName:(NSString *)modelName { self = [super init]; if (self) { _modelName = [modelName copy]; } return self; } - (id) init { return [self initWithModelName:@"Slant 6"]; } - (void)acceptComponentVisitor:(id<NimoComponentVisitor>) visitor { [visitor visitEngine:self]; } - (NSString *)description { return [NSString stringWithFormat:@"Engine: %@", _modelName]; } @end
添加访问支持的Wheel类:
// // NimoWheel.h // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import <Foundation/Foundation.h> #import "NimoComponentVisitor.h" @interface NimoWheel : NSObject @property (nonatomic, assign) float diameter; //直径 - (void)acceptComponentVisitor:(id<NimoComponentVisitor>) visitor; @end
// // NimoWheel.m // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import "NimoWheel.h" @implementation NimoWheel - (id)init { self = [super init]; if (self) { _diameter = 400.0f; } return self; } - (void)acceptComponentVisitor:(id<NimoComponentVisitor>) visitor { [visitor visitWheel:self]; } -(NSString *)description { return [NSString stringWithFormat:@"Wheel: %f mm", _diameter]; } @end
添加访问支持的Car类
// // NimoCar.h // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import <Foundation/Foundation.h> #import "NimoComponentVisitor.h" @class NimoEngine, NimoWheel; @interface NimoCar : NSObject @property (nonatomic) NimoEngine *engine; @property (nonatomic, readonly) NSArray *arrayOfWheels; - (void)addWheel:(NimoWheel *)wheel atIndex:(NSUInteger) index; - (void)acceptComponentVisitor:(id<NimoComponentVisitor>) visitor; @end
// // NimoCar.m // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import "NimoCar.h" #import "NimoEngine.h" #import "NimoWheel.h" @interface NimoCar() @property (nonatomic, readwrite) NSMutableArray *mutableArrayOfWheels; @end @implementation NimoCar - (id)init { if (self = [super init]) { _mutableArrayOfWheels = [[NSMutableArray alloc] initWithCapacity:4]; } return self; } - (void)addWheel:(NimoWheel *)wheel atIndex:(NSUInteger) index { [_mutableArrayOfWheels insertObject:wheel atIndex:index]; } - (NSArray *)arrayOfWheels { return [_mutableArrayOfWheels copy]; } - (void)acceptComponentVisitor:(id<NimoComponentVisitor>) visitor { [_engine acceptComponentVisitor:visitor]; for (NimoWheel *wheel in self.arrayOfWheels) { [wheel acceptComponentVisitor:visitor]; } } - (NSString *)description { return [NSString stringWithFormat:@"My car: %@", [NSDictionary dictionaryWithObjects:@[_engine, self.arrayOfWheels] forKeys:@[@"Engine", @"Wheels"]]]; } @end
我们在类中添加了-(void)acceptComponentVisitor:(id<NimoComponentVisitor>)visitor接口,同意实现了访问者协议的visitor访问。(我家大门常打开,啦啦啦啦啦)
让我们来看下第一位访问者是谁?刚刚上面我们有提到一个需求,想对汽车各组件进行全面升级。那么就让这位专业的访问者来做吧!
定义具体访问者:此访问者具备升级汽车各组件的能力
// // NimoComponentUpgrade.h // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import <Foundation/Foundation.h> #import "NimoComponentVisitor.h" @interface NimoComponentUpgrade : NSObject <NimoComponentVisitor> - (void) visitEngine:(NimoEngine *) engine; - (void) visitWheel:(NimoWheel *) wheel; @end
// // NimoComponentUpgrade.m // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import "NimoComponentUpgrade.h" @implementation NimoComponentUpgrade - (void) visitEngine:(NimoEngine *) engine { NSLog(@"我是升级人员,正在对引擎<%@>进行升级", engine); } - (void) visitWheel:(NimoWheel *) wheel { NSLog(@"我是升级人员,正在对车轮<%@>进行升级", wheel); } @end
让我们来看看这位访问者的工作能力如何
// // main.m // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import <Foundation/Foundation.h> #import "NimoCar.h" #import "NimoEngine.h" #import "NimoWheel.h" #import "NimoComponentMaintenance.h" #import "NimoComponentUpgrade.h" int main(int argc, const char * argv[]) { @autoreleasepool { NimoCar *car = [[NimoCar alloc] init]; NimoEngine *engine = [[NimoEngine alloc] initWithModelName:@"V8"]; NimoWheel *wheelA = [[NimoWheel alloc] init]; NimoWheel *wheelB = [[NimoWheel alloc] init]; NimoWheel *wheelC = [[NimoWheel alloc] init]; NimoWheel *wheelD = [[NimoWheel alloc] init]; car.engine = engine; [car addWheel:wheelA atIndex:0]; [car addWheel:wheelB atIndex:1]; [car addWheel:wheelC atIndex:2]; [car addWheel:wheelD atIndex:3]; NSLog(@"%@", car); //对组建进行“升级” NimoComponentUpgrade *upgradeVisitor = [[NimoComponentUpgrade alloc] init]; [car acceptComponentVisitor:upgradeVisitor]; } return 0; }
看来这位访问者的工作很出色。
如果我们还需要对汽车各组件进行维修呢?那就定义一个专职维修的访问者
// // NimoComponentMaintenance.h // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import <Foundation/Foundation.h> #import "NimoComponentVisitor.h" @interface NimoComponentMaintenance : NSObject <NimoComponentVisitor> - (void) visitEngine:(NimoEngine *) engine; - (void) visitWheel:(NimoWheel *) wheel; @end
// // NimoComponentMaintenance.m // VisitorDemo // // Created by fu zheng on 15/8/12. // Copyright (c) 2015年 FuZheng. All rights reserved. // #import "NimoComponentMaintenance.h" @implementation NimoComponentMaintenance - (void) visitEngine:(NimoEngine *) engine { NSLog(@"我是维修人员,正在对引擎<%@>进行维修", engine); } - (void) visitWheel:(NimoWheel *) wheel { NSLog(@"我是维修人员,正在对车轮<%@>进行维修", wheel); } @end
//main.m ... //对组建进行“维修” NimoComponentMaintenance *maintenanceVisitor = [[NimoComponentMaintenance alloc] init]; [car acceptComponentVisitor:maintenanceVisitor]; ...
使用访问者模式后,添加操作,只需实现具体的访问者,不会对类的结构造成破坏。