软件开发常用设计模式—iOS 中的代理模式总结

比如现在有一个人,想要买一张电影票,但是她很忙碌,没时间去买,那怎么办呢?只能说委托给另一个人去买。

技术分享

此时,需要 person 给 other 发送消息,通知 other 去给她买电影票,而 other 也要反馈消息给 person,此时 other 就是一个代理人,person 委托代理人去办事情(买票)。代理人是给委托人代办一些事情的人。具体代理人怎么做的这些事情,委托人不管,委托人只看反馈。

先看代理设计模式的基本原理

#import <Foundation/Foundation.h>
#import "Agent.h"

@interface Person : NSObject

- (void) buyTicket;

// 拥有一个代理属性
@property (nonatomic, retain) Agent delegate;

@end

一个委托人的类,person 类和 person 类的实现

#import "Person.h"

@implementation Person

// 买电影票
- (void)buyTicket
{
    // 叫代理去帮自己买票(询问一下票价、询问一下票的剩余张数)
    double price = [_delegate ticketPrice];
    int number =  [_delegate leftTicketsNumber];
    
    NSLog(@"通过代理的帮忙,票价=%f,还剩%d张票", price, number);
}

- (void)dealloc
{
    [_delegate release];
    [super dealloc];
}
@end

其中,委托人不亲自去买票,而是让代理人去买票,而具体代理人怎么去办事,委托人不去关心。只需要在委托类里去调对应的代理实现的方法即可。

下面是代理类的实现,其中有代理代办的事情,需要查询剩余票数,和询问票价单价。这些都不需要委托人去做,而是代理给一一代办。

#import "Agent.h"

@implementation Agent

// 剩余的票数
- (int)leftTicketsNumber
{
    // ... 亲自跑电影院\或者打电话
    
    return 1;
}

// 每一张票多少钱
- (double)ticketPrice
{
    // ... 亲自跑电影院\或者打电话
    return 1000;
}
@end

在主方法里,委托人对象 p,p 想去买电影票,但是没时间买,那么好了,让代理去代办这个事情吧,具体怎么办,不管他,只要能买回票就行。然后代理对象 a 。接下来,把代理对象 a 赋值给委托对象 p 的_delegate 成员。然后开始调用买票的方法。

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Agent.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        Person *p = [[Person alloc] init];
        
        Agent *a = [[Agent alloc] init];
        
        p.delegate = a;
        
        [p buyTicket];
    }

    return 0;
}

这样基本上实现了代理设计模式的思路,需要一个委托类的对象p,一个代理类的对象 a,在委托类里声明了代理类的对象delegate,然后把代理类的对象 a 传入委托类 b 中的 delegate,最后让p 给 a 发送消息,本质也就是让 p去调用 a 的方法(使用 p 内的 delegate 调用的 a 的方法)去执行 p 本来想执行的事务。但是,这样的写法,非常不规范,不符合低耦合高内聚的原则!继续分析:

比如,我们把 Agent 类删掉或者哪怕换个名字,那么以后在使用这个代理模式,Person 类就无法发挥作用,就失去了代理设计模式的功能,如果非要用,就需要改变这个架构的代码,尤其是不仅仅需要改变代理类的代码,麻烦的是每次还要修改委托类的代码。这样的话麻烦很大!因为,person类直接依赖了 agent 类。这会使得程序变得耦合度很高!

需要改进代理设计模式:

1、类名不能写死!iOS 中需要使用 id类型(万能指针)代替类类型

2、联想 oc 中的协议语法,需要定义一个协议。因为如果 person 仅仅满足 id 类型,但是不能保证程序知道这个对象里面有什么方法或者属性,那么可以使用协议,只要满足这个协议,那么就可以做我的代理。

3、这样搞,完全是低耦合的设计。要求换代理的时候,仅仅需要增加新的代理累即可,或者删除代理的时候,删除即可。而每次的委托类的代码无需做出任何改变即可满足。

技术分享

如图所示,代理在给人办事情的时候,不是说,想办就可以办,或者说谁想来都能办的,必须要遵循一份我们提供的协议!因为,不遵循协议,鬼知道代理里面有什么方法或者属性呢?你能办什么事情,人都不知道!故必须遵循一份提供的协议,告诉人,代理可以做什么,具体怎么去做,那都是代理的事情了。人不用关心过程,只看结果,事情是办了,还是没办。而人的内部,为了低耦合的实现,把 agent 类型的对象,换成 id 类型,然后让它遵循协议即可。这样就实现了低耦合!代码如下:

#import <Foundation/Foundation.h>
#import "TicketDelegate.h"

@interface Person : NSObject

- (void) buyTicket;

// 拥有一个代理属性
// id代表代理的类名随便
// 但必须遵守TicketDelegate协议
@property (nonatomic, retain) id<TicketDelegate> delegate;

@end

下面是person 的 m 文件

#import "Person.h"

@implementation Person

// 买电影票
- (void)buyTicket
{
    // 叫代理去帮自己买票(询问一下票价、询问一下票的剩余张数)
    double price = [_delegate ticketPrice];
    int number =  [_delegate leftTicketsNumber];
    
    NSLog(@"通过代理的帮忙,票价=%f,还剩%d张票", price, number);
}

- (void)dealloc
{
    [_delegate release];
    [super dealloc];
}
@end

下面是协议的代码,只需要声明一些方法即可。

#import <Foundation/Foundation.h>

// 声明一些方法
@protocol TicketDelegate <NSObject>

// 返回票价
- (double) ticketPrice;

// 还剩多少张票
- (int) leftTicketsNumber;

@end

下面增加一个新的代理类 nextagent,这个代理类,需要遵守这份委托人提供的协议。

#import <Foundation/Foundation.h>
#import "TicketDelegate.h"

@interface NextAgent : NSObject<TicketDelegate>

@end

新代理的实现。

#import "NextAgent.h"

@implementation NextAgent

- (double)ticketPrice
{
    return 500;
}

- (int)leftTicketsNumber
{
    return  10;
}

@end

在 iOS 中的实际应用很多地方都使用了代理设计模式

比如 qq 聊天的表格,是一行行的,或者淘宝客户端展示产品的列表。如下 qq 聊天列表,左边一个头像,右边一般是两行,第一行是昵称,第二行是最近的一段聊天记录显示。

技术分享

整个的屏幕的表格是table,table 里面很多的行,显式的很多行的数据,table 本身不去做这些事情,而是表格控件去做—UITableView很常用的控件,这个控件里面有个 id 类型的数据源 datasource,也就是任何人都能做它的数据元,,但是前提是必须遵守一份它规定的协议——UITableViewDataSource 协议,里面很多方法。这就是代理设计模式的使用。

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。