iOS设计模式之代理模式

一,什么是代理模式

  • 定义

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

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

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

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

  实现步骤

  1. 创建抽象代理类(AbstractProxy),用于定义消息的转发机制和预留的被代理者Customer。
  2. 创建继承于抽象代理类(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
      复制代码
  • 被代理者
    • 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、解耦,代理类和委托代理的直接不需要知道对方做了啥
  • 缺点:代理是一对一的,需要委托者和代理之间签订协议。

五,代码示例
  代理模式

posted on   梁飞宇  阅读(683)  评论(0编辑  收藏  举报

编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示