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