设计思路
- 定义访问者协议:创建一个协议,声明访问不同类型节点的方法,这里即文件和文件夹节点。
- 定义节点基类:创建一个基类表示树节点,包含添加子节点、接受访问者等方法。
- 定义具体节点类:如文件类和文件夹类,继承自节点基类,实现接受访问者方法,调用访问者对应方法。
- 实现具体访问者类:实现访问者协议,在访问文件节点方法中累加文件大小,在访问文件夹节点方法中递归访问子节点。
- 遍历树结构:从根节点开始调用接受访问者方法,传入具体访问者实例。
关键代码片段
- 定义访问者协议
@protocol FileSystemVisitor <NSObject>
- (void)visitFile:(File *)file;
- (void)visitFolder:(Folder *)folder;
@end
- 定义节点基类
@interface FileSystemNode : NSObject
@property (nonatomic, strong) NSMutableArray<FileSystemNode *> *children;
- (void)addChild:(FileSystemNode *)child;
- (void)accept:(id<FileSystemVisitor>)visitor;
@end
@implementation FileSystemNode
- (instancetype)init {
if (self = [super init]) {
_children = [NSMutableArray array];
}
return self;
}
- (void)addChild:(FileSystemNode *)child {
[self.children addObject:child];
}
- (void)accept:(id<FileSystemVisitor>)visitor {
NSAssert(NO, @"Subclasses should implement this method");
}
@end
- 定义具体节点类 - 文件类
@interface File : FileSystemNode
@property (nonatomic, assign) NSInteger size;
- (instancetype)initWithSize:(NSInteger)size;
@end
@implementation File
- (instancetype)initWithSize:(NSInteger)size {
if (self = [super init]) {
_size = size;
}
return self;
}
- (void)accept:(id<FileSystemVisitor>)visitor {
[visitor visitFile:self];
}
@end
- 定义具体节点类 - 文件夹类
@interface Folder : FileSystemNode
- (instancetype)init;
@end
@implementation Folder
- (instancetype)init {
if (self = [super init]) {
}
return self;
}
- (void)accept:(id<FileSystemVisitor>)visitor {
[visitor visitFolder:self];
for (FileSystemNode *child in self.children) {
[child accept:visitor];
}
}
@end
- 实现具体访问者类
@interface FileSizeVisitor : NSObject <FileSystemVisitor>
@property (nonatomic, assign) NSInteger totalSize;
- (instancetype)init;
@end
@implementation FileSizeVisitor
- (instancetype)init {
if (self = [super init]) {
_totalSize = 0;
}
return self;
}
- (void)visitFile:(File *)file {
self.totalSize += file.size;
}
- (void)visitFolder:(Folder *)folder {
// 文件夹本身不占大小,这里只递归访问子节点
for (FileSystemNode *child in folder.children) {
[child accept:self];
}
}
@end
- 遍历树结构并统计文件总大小
Folder *rootFolder = [[Folder alloc] init];
File *file1 = [[File alloc] initWithSize:10];
File *file2 = [[File alloc] initWithSize:20];
Folder *subFolder = [[Folder alloc] init];
File *file3 = [[File alloc] initWithSize:30];
[rootFolder addChild:file1];
[rootFolder addChild:file2];
[rootFolder addChild:subFolder];
[subFolder addChild:file3];
FileSizeVisitor *visitor = [[FileSizeVisitor alloc] init];
[rootFolder accept:visitor];
NSLog(@"Total file size: %ld", (long)visitor.totalSize);