• 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、解耦,代理类和委托代理的直接不需要知道对方做了啥
    • 缺点:代理是一对一的,需要委托者和代理之间签订协议。

    五,代码示例
      代理模式

  • 相关阅读:
    数据结构:练习题
    Node.js尝鲜——留言功能
    html+JavaBean+jsp实现用户注册
    我的安全之路——Web安全篇
    Java模拟储蓄卡和信用卡
    AngularJS尝鲜——联动菜单
    AngularJS尝鲜——Ajax请求
    AngularJS尝鲜——增减商品购买量
    Knight Tournament (set)
    Anniversary party (树形DP)
  • 原文地址:https://www.cnblogs.com/lxlx1798/p/11607712.html
Copyright © 2020-2023  润新知