iOS设计模式之代理模式
一,什么是代理模式
- 定义
为其它对象提供一种代理以控制对这个对象的访问。代理设计模式的英文名是 Proxy pattern,和我们常见的 delegate(委托) 没关系。
-
代理模式的组成
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。百度百科 - 使用场景
在iOS中,我们通常使用代理来做消息的传递,就像我们iOS开发中经常使用的UITableView就是使用了代理,来创建cell,点击cell等一系列的操作
二,代理模式结构图(消息转发式的代理实现)
实现步骤:
- 创建抽象代理类(AbstractProxy),用于定义消息的转发机制和预留的被代理者Customer。
- 创建继承于抽象代理类(AbstractProxy)的子类(ConcreteProxy),主要用于转发代理消息。
结构图:
三,代码实现
- 消息转发类
- AbstractProxy.h
@interface AbstractProxy : NSProxy /** * 被代理对象 */ @property (nonatomic,weak) id customer; /** * @breif 代理客户 * @param customer 实现了某种协议的客户 * @return 代理对象 */ - (instancetype)initWithCustomer:(id)customer; @end
- AbstractProxy.m
#import <objc/runtime.h> #import "AbstractProxy.h" #import "AbstractExcute.h" @implementation AbstractProxy - (instancetype)initWithCustomer:(id)customer { self.customer = customer; return self; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aselector { if ([self.customer respondsToSelector:aselector]) { return [self.customer methodSignatureForSelector:aselector]; } else { AbstractExcute *excute = [AbstractExcute shareInstance]; return [excute methodSignatureForSelector:NSSelectorFromString(@"nullExcute:")]; } } - (void)forwardInvocation:(NSInvocation *)invocation { SEL selector = [invocation selector]; if ([self.customer respondsToSelector:selector]) { [invocation setTarget:self.customer]; [invocation invoke]; } else { NSString *selectorString = NSStringFromSelector(invocation.selector); invocation.selector = NSSelectorFromString(@"nullExcute:"); AbstractExcute *excute = [AbstractExcute shareInstance]; [invocation setTarget:excute]; const char *className = class_getName([self class]); NSArray *classNameArray = nil; if (self.customer) { classNameArray = @[[NSString stringWithUTF8String:className], selectorString, @""]; } else { classNameArray = @[[NSString stringWithUTF8String:className], selectorString]; } [invocation setArgument:&classNameArray atIndex:2]; [invocation invoke]; } } @end
- AbstractProxy.h
- 被代理者
- ConcreteProxy.h
#import "AbstractProxy.h" #import "MessageProtocol.h" NS_ASSUME_NONNULL_BEGIN @interface ConcreteProxy : AbstractProxy<MessageProtocol> @end NS_ASSUME_NONNULL_END
- ConcreteProxy.m
#import "ConcreteProxy.h" @implementation ConcreteProxy @end
- ConcreteProxy.h
- 异常处理者
- AbstractExcute.h
#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface AbstractExcute : NSObject + (instancetype)shareInstance; @end NS_ASSUME_NONNULL_END
- AbstractExcute.m
#import "AbstractExcute.h" @implementation AbstractExcute + (instancetype)shareInstance { static AbstractExcute *sharedAbstractExcute = nil; static dispatch_once_t predicate; dispatch_once(&predicate, ^{ sharedAbstractExcute = [[self alloc]init]; }); return sharedAbstractExcute; } - (void)nullExcute:(NSArray *)className { if (className.count == 3) { NSLog(@"%@ 设置了代理,但该代理没有实现 %@ 方法", className[0], className[1]); } else { NSLog(@"%@ 没有设置代理,方法 %@ 没有执行", className[0], className[1]); } } @end
- AbstractExcute.h
- 异常处理者
- ViewController.h
#import <UIKit/UIKit.h> @interface ViewController : UIViewController @end
- ViewController.m
#import "ViewController.h" #import "MessageProtocol.h" #import "ConcreteProxy.h" @interface ViewController ()<MessageProtocol> @property(nonatomic,strong) ConcreteProxy *proxy; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.proxy = [[ConcreteProxy alloc]initWithCustomer:self]; [self.proxy helloWorld]; [self.proxy goodByte]; } - (void)helloWorld { NSLog(@"helloWorld"); } - (void)goodByte { NSLog(@"goodByte"); } @end
- ViewController.h
四,优缺点
- 优点:
1、职责清晰:就是真实的角色不需要知道代理做的细节,只要知道结果,就是说,我不需要知道中介怎么匹配适合我的房源,这些匹配的过程只需要交给代理来做,我只要知道哪些房源适合我就可以了。
2、有很高的扩展性
3、代理对象和我们的真实对象和目标对象之间只是起到中介的作用。
4、解耦,代理类和委托代理的直接不需要知道对方做了啥
- 缺点:代理是一对一的,需要委托者和代理之间签订协议。
五,代码示例
代理模式