iOS 设计模式的应用 ⑳ 代理模式
前言
在 Windows 系统中,我们安装软件时,常常会遇见在桌面安装快捷方式,让我们更快捷的找到它,当我们运行它时实际上是访问到了该文件的实际位置。在 Mac 中也有这种设计叫做替身。如果我们不创建快捷方式,就要去寻找应用程序所在的真实路径,才可以运行,这会给我们带来许多的麻烦。
在面向对象的软件设计中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。从这一思想细化而来的一种设计模式叫做代理模式。
什么是代理模式
代理模式为其他对象提供一种代理以控制对这个对象的访问。通常,代理是一种替代或者占位,它控制对另一些对象的访问,而这些对象可能是远程对象、创建开销较大的对象,或者是对安全性有要求的对象。代理模式的思想是使用一个基本上跟实体对象行为相同的代理。客户端可以透明地使用代理,不必执行所面对的只是一个代理而不是实体对象。当客户端请求某些创建开销较大的功能时,代理将把请求转发给实体对象,准备好请求的功能并返回给客户端。

当客户端向 Proxy
对象发送request
消息时,Proxy
对象会把这个消息转发给 Proxy
对象之中的 RealSubject
对象。 RealSubject
会实施实际的操作间接满足客户端的请求。
什么时候使用代理模式
- 远程代理
- 虚拟代理
- 保护代理
- Cache 代理
- 防火墙代理
- 同步化代理
- 智能引用代理
代理模式的优缺点
代理模式的优点
- 职责清晰。
- 高扩展性。
- 智能化。
代理模式的缺点
- 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
- 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
Cocoa 中的代理模式
NSProxy
是 Cocoa 框架中如 NSObject
一样的根类,定义了充当其他对象代理的对象的接口,即使对于尚不存在的对象也是如此。代理对象通常将发送给它的消息转发给它所代表的对象,但它也可以通过加载所表示的对象或将自己转换成它来响应消息。虽然NSProxy
是一个抽象类,但它实现NSObject
了根对象所期望的协议和其他基本方法,NSProxy
的具体子类可以实现代理模式的既定目标。
代理模式的实现
声明一个 <Image> 协议
@protocol Image <NSObject>
- (void)display;
@end
创建一个 RealImage 实体类
@interface RealImage : NSObject<Image>
- (instancetype)initWithFileName:(NSString *)fileName;
@end
@implementation RealImage
{
NSString *_fileName;
}
- (instancetype)initWithFileName:(NSString *)fileName
{
self = [super init];
if (self) {
_fileName = fileName;
}
return self;
}
- (void)display{
NSLog(@"display%@",_fileName);
}
- (void)loadFromDisk{
NSLog(@"loadFrom%@",_fileName);
}
@end
创建一个 ProxyImage
代理类
@interface ProxyImage : NSProxy<Image>
- (instancetype)initWithFileName:(NSString *)fileName;
@end
@implementation ProxyImage{
RealImage *_realImage;
NSString *_fileName;
}
- (instancetype)initWithFileName:(NSString *)fileName
{
_fileName = fileName;
return self;
}
- (void)forwardInvocation:(NSInvocation *)invocation{
SEL aSelector = [invocation selector];
if (_realImage && [_realImage respondsToSelector:aSelector]) {
[invocation invokeWithTarget:_realImage];
}else{
[super forwardInvocation:invocation];
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
if (!_realImage) {
_realImage = [[RealImage alloc] initWithFileName:_fileName];
}
if ([_realImage respondsToSelector:sel]) {
NSMethodSignature *signature = [_realImage methodSignatureForSelector:sel];
return signature;
}
return [super methodSignatureForSelector:sel];
}
@end
总结
代理对象,以控制对另一个对象的访问,该对象可能是远程的、创建成本高昂或需要保护。这种模式在结构上类似于装饰器模式,但它的用途不同;装饰器向对象添加行为,而代理控制对对象的访问。
在 iOS 应用开发中,总是要关注内存的使用量。不论应用程序运行在何种 iOS 设备上,出于性能的考虑,总是推荐懒加载技术。可以在 iOS 应用中使用代理模式,对开销大的数据实现懒加载,如大图像文件或者通过低俗网络从服务器下载的大型数据。如果大开销的对象在收到请求之间不需要加载,通过虚拟代理向客户端提供某些轻量信息。