MST

星途 面试题库

面试题:Objective-C组合模式与其他设计模式的结合及场景分析

在Objective-C开发中,说明组合模式与代理模式结合在何种场景下能发挥最大优势,并详细阐述结合的实现方式及可能面临的问题与解决方案。要求给出具体代码示例及应用场景的实际业务描述。
15.4万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

1. 适用场景

在复杂对象的构建与行为分发场景下,组合模式与代理模式结合能发挥最大优势。例如在一个大型游戏开发中,游戏场景由许多不同类型的游戏对象(如角色、道具、建筑等)组成,这些对象形成一个树形结构(组合模式)。同时,游戏对象的一些操作(如渲染、交互逻辑)可能由于性能、平台适配等原因,需要通过代理来间接执行。

2. 实现方式

组合模式

定义一个抽象组件类 Component,有抽象方法用于操作组件及其子组件。具体组件类 Composite 继承 Component,并管理子组件列表,实现添加、移除子组件方法。叶子组件类 Leaf 继承 Component,实现具体操作。

// 抽象组件类
@interface Component : NSObject
@property (nonatomic, strong) NSString *name;
- (instancetype)initWithName:(NSString *)name;
- (void)operation;
@end

@implementation Component
- (instancetype)initWithName:(NSString *)name {
    if (self = [super init]) {
        _name = name;
    }
    return self;
}
- (void)operation {
    NSLog(@"Component %@ operation", self.name);
}
@end

// 组合组件类
@interface Composite : Component
@property (nonatomic, strong) NSMutableArray<Component *> *children;
- (void)addChild:(Component *)child;
- (void)removeChild:(Component *)child;
@end

@implementation Composite
- (instancetype)initWithName:(NSString *)name {
    if (self = [super initWithName:name]) {
        _children = [NSMutableArray array];
    }
    return self;
}
- (void)addChild:(Component *)child {
    [self.children addObject:child];
}
- (void)removeChild:(Component *)child {
    [self.children removeObject:child];
}
- (void)operation {
    NSLog(@"Composite %@ operation", self.name);
    for (Component *child in self.children) {
        [child operation];
    }
}
@end

// 叶子组件类
@interface Leaf : Component
@end

@implementation Leaf
- (void)operation {
    NSLog(@"Leaf %@ operation", self.name);
}
@end

代理模式

定义一个代理协议 ProxyProtocol,代理类 Proxy 实现该协议,持有被代理对象 RealSubject 实例。当调用代理对象方法时,实际转发给被代理对象。

// 代理协议
@protocol ProxyProtocol <NSObject>
- (void)doSomething;
@end

// 真实对象类
@interface RealSubject : NSObject <ProxyProtocol>
- (void)doSomething;
@end

@implementation RealSubject
- (void)doSomething {
    NSLog(@"RealSubject do something");
}
@end

// 代理类
@interface Proxy : NSObject <ProxyProtocol>
@property (nonatomic, strong) RealSubject *realSubject;
- (instancetype)initWithRealSubject:(RealSubject *)realSubject;
- (void)doSomething;
@end

@implementation Proxy
- (instancetype)initWithRealSubject:(RealSubject *)realSubject {
    if (self = [super init]) {
        _realSubject = realSubject;
    }
    return self;
}
- (void)doSomething {
    NSLog(@"Proxy before do something");
    [self.realSubject doSomething];
    NSLog(@"Proxy after do something");
}
@end

结合方式

Component 类或其子类中使用代理对象来执行特定操作。例如在 Leaf 类中,可以将某些操作通过代理执行。

@interface Leaf : Component
@property (nonatomic, strong) Proxy *proxy;
@end

@implementation Leaf
- (void)operation {
    NSLog(@"Leaf %@ operation", self.name);
    if (self.proxy) {
        [self.proxy doSomething];
    }
}
@end

3. 可能面临的问题与解决方案

问题

  • 性能问题:过多代理嵌套可能导致性能开销增大,因为每次调用都需要经过代理转发。
  • 维护复杂性:组合模式和代理模式结合后,代码结构变得复杂,增加了维护难度。例如,当代理对象或组合结构发生变化时,可能需要在多个地方进行修改。

解决方案

  • 性能优化:尽量减少不必要的代理嵌套,对频繁调用的方法考虑直接在组件内实现而不是通过代理。
  • 提高可维护性:采用清晰的代码结构和良好的注释,例如将代理相关操作封装在独立的类或方法中,使得组合模式和代理模式的代码逻辑尽量分离。在进行结构或逻辑变更时,通过设计合理的接口和抽象类,降低对其他部分代码的影响。

4. 具体业务描述

以电商APP的商品展示模块为例。商品展示页面由不同类型的组件构成,如商品图片、商品标题、商品描述等,这些组件形成一个组合结构(组合模式)。而图片的加载操作,由于涉及到网络请求、缓存管理等复杂逻辑,为了提高性能和可维护性,可以通过代理模式来处理。图片组件(叶子组件)持有图片加载代理对象,当需要加载图片时,通过代理对象来执行加载操作,代理对象可以进行缓存检查、网络请求管理等额外逻辑。