面向对象设计模式--代理模式(C++可执行代码)

代理模式

(Proxy)

        代理 是一种结构型设计模式,让你能够提供对象的替代品或其占位符。代理控制着对于原对象的访问,并允许在将请求提交给对象前后进行一些处理。、

1. 问题 

        为什么要控制对于某个对象的访问呢?举个例子:有这样一个消耗大量系统资源的巨型对象, 你只是偶尔需要使用它,并非总是需要。

数据库查询有可能会非常缓慢。

        你可以实现延迟初始化:在实际有需要时再创建该对象。对象的所有客户端都要执行延迟初始代码。不幸的是,这很可能会带来很多重复代码。

        在理想情况下,我们希望将代码直接放入对象的类中,但这并非总是能实现:比如类可能是第三方封闭库的一部分。

2. 解决方案

        代理模式建议新建一个与原服务对象接口相同的代理类,然后更新应用以将代理对象传递给所有原始对象客户端。代理类接收到客户端请求后会创建实际的服务对象,并将所有工作委派给它。

        代理将自己伪装成数据库对象,可在客户端或实际数据库对象不知情的情况下处理延迟初始化和缓存查询结果的工作。

        这有什么好处呢?如果需要在类的主要业务逻辑前后执行一些工作,你无需修改类就能完成这项工作。由于代理实现的接口与原类相同,因此你可将其传递给任何一个使用实际服务对象的客户端。

3. 结构

代理模式的结构

        其中:

        *Proxy保存一个引用使得代理可以访问实体; 提供一个与Subject的接口相同的接口,使代理可以用来代替实体;控制对实体的存取,并可能负责创建和删除它;其他功能依赖于代理的类型:Remote Proxy负责对请求及其参数进行编码, 并向不同地址空间中的实体发送已编码的请求; Virtual Proxy可以缓存实体的附加信息, 以便延迟对它的访问; Protection Proxy检查调用者是否具有实现一个请求所必需的访问权限。

        *Subject定义Real Subject和Proxy的共用接口, 这样就在任何使用Real Subject的地方都可以使用Proxy。

        *Real Subject定义Proxy所代表的实体。

4. 实现方式

1. 如果没有现成的服务接口,你就需要创建一个接口来实现代 理和服务对象的可交换性。

        从服务类中抽取接口并非总是可行的,因为你需要对服务的所有客户端进行修改,让它们使用接口。备选计划是将代理作为服务类的子类,这样代理就能继承服务的所有接口了。

2. 创建代理类,其中必须包含一个存储指向服务的引用的成员变量。

        通常情况下,代理负责创建服务并对其整个生命周期进行管理。在一些特殊情况下,客户端会通过构造函数将服务传递给代理。

3. 根据需求实现代理方法。

        在大部分情况下,代理在完成一些任务后应将工作委派给服务对象。

4. 可以考虑新建一个构建方法来判断客户端可获取的是代理还是实际服务。

        你可以在代理类中创建一个简单的静态方法,也可以创建一个完整的工厂方法。

5. 可以考虑为服务对象实现延迟初始化。

5. 代码示例

proxyt.h

#ifndef DESIGN_PATTERNS_PROXY_H
#define DESIGN_PATTERNS_PROXY_H

#include <iostream>
#include <string>
using namespace std;
//------------------------------//
class SchoolGirl //"校园女生"类
{
public:
	SchoolGirl() {}
	SchoolGirl(string);
	string GetName();
private:
	string name_;
};
//------------------------------//
class GiveGift //"给礼物"接口类
{
public:
	virtual void GiveFlowers() = 0;
	virtual void GiveDolls() = 0;
};

class Pursuit : public GiveGift //"追求"类
{
public:
	Pursuit() {}
	Pursuit(SchoolGirl *);
	void GiveFlowers();
	void GiveDolls();

private:
	SchoolGirl *school_girl_;
};

class Proxy : public GiveGift //"代理"类
{
public:
	Proxy() {}
	Proxy(SchoolGirl *);
	~Proxy();
	void GiveFlowers();
	void GiveDolls();

private:
	Pursuit *pursuit_;
};
//------------------------------//
#endif //DESIGN_PATTERNS_PROXY_H

proxyt.c

#include "proxy.h"
//------------------------------//
SchoolGirl::SchoolGirl(string name) : name_(name) {}

string SchoolGirl::GetName() 
{
	return name_;
}
//------------------------------//
Pursuit::Pursuit(SchoolGirl *school_girl) : school_girl_(school_girl){}

void Pursuit::GiveFlowers() 
{
	cout << "花朵给 " << school_girl_->GetName() << endl;
}

void Pursuit::GiveDolls() 
{
	cout << "美元给 " << school_girl_->GetName() << endl;
}
//------------------------------//
Proxy::Proxy(SchoolGirl *school_girl) 
{
	pursuit_ = new Pursuit(school_girl);
}

Proxy::~Proxy() 
{
	delete pursuit_;
}

void Proxy::GiveFlowers() 
{
	pursuit_->GiveFlowers();
}

void Proxy::GiveDolls() 
{
	pursuit_->GiveDolls();
}
//------------------------------//

Main.c

打印输出

6. 应用场景

延迟初始化(虚拟代理)。如果你有一个偶尔使用的重量级服务对象,一直保持该对象运行会消耗系统资源时,可使用代理模式。

        你无需在程序启动时就创建该对象,可将对象的初始化延迟到真正有需要的时候。

访问控制(保护代理)。如果你只希望特定客户端使用服务对象,这里的对象可以是操作系统中非常重要的部分,而客户端则是各种已启动的程序(包括恶意程序),此时可使用代理模式。

        代理可仅在客户端凭据满足要求时将请求传递给服务对象。

本地执行远程服务(远程代理)。适用于服务对象位于远程服务器上的情形。

        在这种情形中,代理通过网络传递客户端请求,负责处理所有与网络相关的复杂细节。

记录日志请求(日志记录代理)。适用于当你需要保存对于服务对象的请求历史记录时。代理可以在向服务传递请求前进行记录。

        缓存请求结果(缓存代理)。适用于需要缓存客户请求结果并对缓存生命周期进行管理时,特别是当返回结果的体积非常大时。

        • 代理可对重复请求所需的相同结果进行缓存,还可使用请求参数作为索引缓存的键值。

智能引用。可在没有客户端使用某个重量级对象时立即销毁该对象。

        代理会将所有获取了指向服务对象或其结果的客户端记录在案。代理会时不时地遍历各个客户端,检查它们是否仍在运行。如果相应的客户端列表为空,代理就会销毁该服务对象,释放底层系统资源。

7. 优缺点

        √ 你可以在客户端毫无察觉的情况下控制服务对象。

        √ 如果客户端对服务对象的生命周期没有特殊要求,你可以对生命周期进行管理。

        √ 即使服务对象还未准备好或不存在,代理也可以正常工作。

        √ 开闭原则。你可以在不对服务或客户端做出修改的情况下创建新代理。

        × 代码可能会变得复杂,因为需要新建许多类。

        × 服务响应可能会延迟。

8. 与其他模式的关系

        • 适配器能为被封装对象提供不同的接口,代理能为对象提供相同的接口,装饰则能为对象提供加强的接口。

        • 外观与代理的相似之处在于它们都缓存了一个复杂实体并自行对其进行初始化。代理与其服务对象遵循同一接口,使得自己和服务对象可以互换,在这一点上它与外观不同。

        • 装饰和代理有着相似的结构,但是其意图却非常不同。这两个模式的构建都基于组合原则,也就是说一个对象应该将部分工作委派给另一个对象。两者之间的不同之处在于代理通常自行管理其服务对象的生命周期,而装饰的生成则总是由客户端进行控制。

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值