MST

星途 面试题库

面试题:Objective-C访问者模式在复杂数据结构中的应用

假设有一个复杂的Objective-C对象树结构,每个节点对象有不同的属性和行为,例如有文件系统树结构,文件和文件夹是不同的节点类型。请使用访问者模式实现对这个对象树的遍历,以实现统计文件总大小的功能。详细阐述设计思路,并给出关键代码片段。
17.3万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 定义访问者协议:创建一个协议,声明访问不同类型节点的方法,这里即文件和文件夹节点。
  2. 定义节点基类:创建一个基类表示树节点,包含添加子节点、接受访问者等方法。
  3. 定义具体节点类:如文件类和文件夹类,继承自节点基类,实现接受访问者方法,调用访问者对应方法。
  4. 实现具体访问者类:实现访问者协议,在访问文件节点方法中累加文件大小,在访问文件夹节点方法中递归访问子节点。
  5. 遍历树结构:从根节点开始调用接受访问者方法,传入具体访问者实例。

关键代码片段

  1. 定义访问者协议
@protocol FileSystemVisitor <NSObject>
- (void)visitFile:(File *)file;
- (void)visitFolder:(Folder *)folder;
@end
  1. 定义节点基类
@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
  1. 定义具体节点类 - 文件类
@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
  1. 定义具体节点类 - 文件夹类
@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
  1. 实现具体访问者类
@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
  1. 遍历树结构并统计文件总大小
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);