MST
星途 面试题库

面试题:Objective-C 备忘录模式在复杂业务场景中的应用

假设你正在开发一个iOS绘图应用,用户可以绘制图形并进行撤销操作。请使用Objective-C的备忘录模式来设计该撤销功能,说明每个类的职责以及如何保证性能和内存管理,同时要考虑到不同图形对象的状态保存与恢复。
17.7万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

1. 定义备忘录类(Memento)

  • 职责:用于保存绘图对象(图形)的状态。
@interface DrawingMemento : NSObject
@property (nonatomic, strong) id state; // 保存图形状态,不同图形状态类型不同
- (instancetype)initWithState:(id)state;
@end

@implementation DrawingMemento
- (instancetype)initWithState:(id)state {
    self = [super init];
    if (self) {
        _state = state;
    }
    return self;
}
@end

2. 定义绘图对象类(Originator)

  • 职责:创建备忘录以保存自身状态,从备忘录中恢复自身状态。
@interface DrawingObject : NSObject
@property (nonatomic, strong) id currentState; // 当前图形状态
- (DrawingMemento *)saveState;
- (void)restoreState:(DrawingMemento *)memento;
@end

@implementation DrawingObject
- (DrawingMemento *)saveState {
    return [[DrawingMemento alloc] initWithState:self.currentState];
}

- (void)restoreState:(DrawingMemento *)memento {
    self.currentState = memento.state;
}
@end

3. 定义负责人类(Caretaker)

  • 职责:负责管理备忘录,维护一个备忘录的栈,用于实现撤销操作。
@interface DrawingCaretaker : NSObject
@property (nonatomic, strong) NSMutableArray<DrawingMemento *> *mementoStack;
- (void)pushMemento:(DrawingMemento *)memento;
- (DrawingMemento *)popMemento;
@end

@implementation DrawingCaretaker
- (instancetype)init {
    self = [super init];
    if (self) {
        _mementoStack = [NSMutableArray array];
    }
    return self;
}

- (void)pushMemento:(DrawingMemento *)memento {
    [self.mementoStack addObject:memento];
}

- (DrawingMemento *)popMemento {
    if (self.mementoStack.count > 0) {
        DrawingMemento *memento = self.mementoStack.lastObject;
        [self.mementoStack removeLastObject];
        return memento;
    }
    return nil;
}
@end

4. 性能和内存管理

  • 性能
    • 备忘录栈使用NSMutableArray,添加和删除操作平均时间复杂度为 O(1),保证了撤销操作的高效性。
    • 对于不同图形对象,状态保存与恢复操作尽量做到原子化,减少不必要的计算开销。
  • 内存管理
    • DrawingMementoDrawingObjectDrawingCaretaker 都遵循ARC(自动引用计数)规则,对象创建和销毁由系统自动管理,避免了手动内存管理的错误。
    • 当不再需要保存的状态时(例如用户清空绘图历史),可以通过清空 DrawingCaretaker 的备忘录栈来释放内存。

5. 不同图形对象的状态保存与恢复

  • 不同图形对象(如圆形、矩形等)可以继承自 DrawingObject 类。
  • 对于每个具体图形对象,在 saveState 方法中保存其特定的状态属性(如圆形的半径、矩形的长宽等),在 restoreState 方法中恢复这些属性。例如:
@interface Circle : DrawingObject
@property (nonatomic, CGFloat) radius;
@end

@implementation Circle
- (DrawingMemento *)saveState {
    NSMutableDictionary *stateDict = [NSMutableDictionary dictionary];
    stateDict[@"radius"] = @(self.radius);
    return [[DrawingMemento alloc] initWithState:stateDict];
}

- (void)restoreState:(DrawingMemento *)memento {
    NSDictionary *stateDict = memento.state;
    self.radius = [stateDict[@"radius"] floatValue];
}
@end

同样,矩形等其他图形对象也可类似实现。这样就可以实现不同图形对象状态的保存与恢复,同时利用备忘录模式实现绘图应用的撤销功能。