前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面向对象设计的设计模式(十):代理模式

面向对象设计的设计模式(十):代理模式

作者头像
用户2932962
发布2019-04-25 15:14:05
4590
发布2019-04-25 15:14:05
举报
文章被收录于专栏:程序员维他命程序员维他命

定义

代理模式(Proxy Pattern) :为某个对象提供一个代理,并由这个代理对象控制对原对象的访问。

定义解读:使用代理模式以后,客户端直接访问代理,代理在客户端和目标对象之间起到中介的作用。

适用场景

在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。

因为代理对象可以在客户端和目标对象之间起到中介的作用,因此可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。

根据业务的不同,代理也可以有不同的类型:

  • 远程代理:为位于不同地址或网络化中的对象提供本地代表。
  • 虚拟代理:根据要求创建重型的对象。
  • 保护代理:根据不同访问权限控制对原对象的访问。

下面来看一下代理模式的成员和类图。

成员与类图

成员

代理模式算上客户端一共有四个成员:

  • 客户端(Client):客户端意图访问真是主体接口
  • 抽象主题(Subejct):抽象主题定义客户端需要访问的接口
  • 代理(Proxy):代理继承于抽象主题,目的是为了它持有真实目标的实例的引用,客户端直接访问代理
  • 真实主题(RealSubject):真实主题即是被代理的对象,它也继承于抽象主题,它的实例被代理所持有,它的接口被包装在了代理的接口中,而且客户端无法直接访问真实主题对象。

其实我也不太清楚代理模式里面为什么会是Subject和RealSubject这个叫法。

下面通过类图来看一下各个成员之间的关系:

模式类图

代理模式类图

从类图中可以看出,工厂类提供一个静态方法:通过传入的字符串来制造其所对应的产品。

代码示例

场景概述

在这里举一个买房者通过买房中介买房的例子。

现在一般我们买房子不直接接触房东,而是先接触中介,买房的相关合同和一些事宜可以先和中介进行沟通。

在本例中,我们在这里让买房者直接支付费用给中介,然后中介收取一部分的中介费, 再将剩余的钱交给房东。

场景分析

中介作为房东的代理,与买房者直接接触。而且中介还需要在真正交易前做其他的事情(收取中介费,帮买房者check房源的真实性等等),因此该场景比较适合使用代理模式。

根据上面的代理模式的成员:

  • 客户端就是买房者
  • 代理就是中介
  • 真实主题就是房东
  • 中介和房东都会实现收钱的方法,我们可以定义一个抽象主题类,它有一个公共接口是收钱的方法。

代码实现

首先我们定义一下房东和代理需要实现的接口PaymentInterface(在类图里面是继承某个共同对象,我个人比较习惯用接口来做)。

代码语言:javascript
复制
//================== PaymentInterface.h ==================

@protocol PaymentInterface <NSObject>

- (void)getPayment:(double)money;

@end

这个接口声明了中介和房东都需要实现的方法getPayment:

接着我们声明代理类HouseProxy:

代码语言:javascript
复制
//================== HouseProxy.h ==================

@interface HouseProxy : NSObject<PaymentInterface>

@end




//================== HouseProxy.m ==================
const float agentFeeRatio = 0.35;

@interface HouseProxy()

@property (nonatomic, copy) HouseOwner *houseOwner;

@end

@implementation HouseProxy

- (void)getPayment:(double)money{

    double agentFee = agentFeeRatio * money;
    NSLog(@"Proxy get payment : %.2lf",agentFee);

    [self.houseOwner getPayment:(money - agentFee)];
}

- (HouseOwner *)houseOwner{

    if (!_houseOwner) {
         _houseOwner = [[HouseOwner alloc] init];
    }
    return _houseOwner;
}

@end

HouseProxy里面,持有了房东,也就是被代理者的实例。然后在的getPayment:方法里,调用了房东实例的getPayment:方法。而且我们可以看到,在调用房东实例的getPayment:方法,代理先拿到了中介费(中介费比率agentFeeRatio定义为0.35,即中介费的比例占35%)。

这里面除了房东实例的getPayment:方法之外的一些操作就是代理存在的意义:它可以在真正被代理对象做事情之前,之后做一些其他额外的事情。比如类似AOP编程一样,定义类似的before***Method或是after**Method方法等等。

最后我们看一下房东是如何实现getPayment:方法的:

代码语言:javascript
复制
//================== HouseOwner.h ==================

@interface HouseOwner : NSObject<PaymentInterface>

@end




//================== HouseOwner.m ==================

@implementation HouseOwner

- (void)getPayment:(double)money{

    NSLog(@"House owner get payment : %.2lf",money);
}

@end

房东类HouseOwner按照自己的方式实现了getPayment:方法。

很多时候被代理者(委托者)可以完全按照自己的方式去做事情,而把一些额外的事情交给代理来做,这样可以保持原有类的功能的纯粹性,符合开闭原则。

下面我们看一下客户端的使用以及打印出来的结果:

客户端代码:

代码语言:javascript
复制
//================== client.m ==================

HouseProxy *proxy = [[HouseProxy alloc] init];
[proxy getPayment:100];

上面的客户端支付给了中介100元。

下面我们看一下打印结果:

代码语言:javascript
复制
Proxy get payment : 35.00
House owner get payment : 65.00

和预想的一样,中介费收取了35%的中介费,剩下的交给了房东。

代码对应的类图

代理模式代码示例类图

从UML类图中我们可以看出,在这里没有使用抽象主题对象,而是用一个接口来分别让中介和房东实现。

优点

  • 降低系统的耦合度:代理模式能够协调调用者和被调用者,在一定程度上降低了系 统的耦合度。
  • 不同类型的代理可以对客户端对目标对象的访问进行不同的控制:
    • 远程代理,使得客户端可以访问在远程机器上的对象,远程机器 可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。
    • 虚拟代理通过使用一个小对象来代表一个大对象,可以减少系统资源的消耗,对系统进行优化并提高运行速度。
    • 保护代理可以控制客户端对真实对象的使用权限。

缺点

  • 由于在客户端和被代理对象之间增加了代理对象,因此可能会让客户端请求的速度变慢。

Objective-C & Java的实践

  • iOS SDK:NSProxy可以为持有的对象进行消息转发
  • JDK:AOP下的JDKDynamicAopProxy是对JDK的动态代理进行了封装
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员维他命 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义
  • 适用场景
  • 成员与类图
    • 成员
      • 模式类图
      • 代码示例
        • 场景概述
          • 场景分析
            • 代码实现
              • 代码对应的类图
              • 优点
              • 缺点
              • Objective-C & Java的实践
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档