iOS设计模式之代理模式

一,什么是代理模式

  • 定义

    为其它对象提供一种代理以控制对这个对象的访问。代理设计模式的英文名是 Proxy pattern,和我们常见的 delegate(委托) 没关系。

  • 代理模式的组成
    抽象角色:通过接口或抽象类声明真实角色实现的业务方法。 
    代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。 
    真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。百度百科

  • 使用场景
    在iOS中,我们通常使用代理来做消息的传递,就像我们iOS开发中经常使用的UITableView就是使用了代理,来创建cell,点击cell等一系列的操作

二,代理模式结构图(消息转发式的代理实现)  

  实现步骤

  1. 创建抽象代理类(AbstractProxy),用于定义消息的转发机制和预留的被代理者Customer。
  2. 创建继承于抽象代理类(AbstractProxy)的子类(ConcreteProxy),主要用于转发代理消息。

  结构图
  iOS设计模式之代理模式

三,代码实现

  • 消息转发类
    • 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
  • 被代理者
    • 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
  • 异常处理者
    • 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
  • 异常处理者
    • 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

四,优缺点

  • 优点
    1、职责清晰:就是真实的角色不需要知道代理做的细节,只要知道结果,就是说,我不需要知道中介怎么匹配适合我的房源,这些匹配的过程只需要交给代理来做,我只要知道哪些房源适合我就可以了。 
    2、有很高的扩展性 
    3、代理对象和我们的真实对象和目标对象之间只是起到中介的作用。 
    4、解耦,代理类和委托代理的直接不需要知道对方做了啥
  • 缺点:代理是一对一的,需要委托者和代理之间签订协议。

五,代码示例
  代理模式

iOS设计模式之代理模式

上一篇:js中如果遇到低版本安卓设备调用setTimeout不生效解决办法


下一篇:uni-app通过判断接口403跳转登录页面的问题