设计模式之代理模式(二)
下面通过一个应用实例来进一步学习和理解代理模式。
- 实例说明
某软件公司承接了某信息咨询公司的收费商务信息查询系统的开发任务,该系统的基本需求如下:
(1) 在进行商务信息查询之前用户需要通过身份验证,只有合法用户才能够使用该查询系统;
(2) 在进行商务信息查询时系统需要记录查询日志,以便根据查询次数收取查询费用。
该软件公司开发人员已完成了商务信息查询模块的开发任务,现希望能够以一种松耦合的方式向原有系统增加身份验证和日志记录功能,客户端代码可以无区别地对待原始的商务信息查询模块和增加新功能之后的商务信息查询模块,而且可能在将来还要在该信息查询模块中增加一些新的功能。
试使用代理模式设计并实现该收费商务信息查询系统。
- 实例分析及类图
图15-3 商务信息查询系统设计方案示意图
在图15-3中,客户端对象通过代理对象间接访问具有商务信息查询功能的真实对象,在代理对象中除了调用真实对象的商务信息查询功能外,还增加了身份验证和日志记录等功能。使用代理模式设计该商务信息查询系统,结构图如图15-4所示。
图15-4 商务信息查询系统结构图
在图15-4中,业务类AccessValidator用于验证用户身份,业务类Logger用于记录用户查询日志,Searcher充当抽象主题角色,RealSearcher充当真实主题角色,ProxySearcher充当代理主题角色。
- 实例代码
(2) Logger:日志记录类,业务类,它提供方法Log()来保存日志。
using System;
namespace ProxySample
{
class Logger
{
//模拟实现日志记录
public void Log(string userId) {
Console.WriteLine("更新数据库,用户'{0}'查询次数加1!",userId);
}
(3) Searcher:抽象查询类,充当抽象主题角色,它声明了DoSearch()方法。
(4) RealSearcher:具体查询类,充当真实主题角色,它实现查询功能,提供方法DoSearch()来查询信息。
//RealSearcher.cs
using System;
namespace ProxySample
{
class RealSearcher : Searcher
{
//模拟查询商务信息
public string DoSearch(string userId, string keyword) {
Console.WriteLine("用户'{0}'使用关键词'{1}'查询商务信息!",userId,keyword);
return "返回具体内容";
}
}
(5) ProxySearcher:代理查询类,充当代理主题角色,它是查询代理,维持了对RealSearcher对象、AccessValidator对象和Logger对象的引用。
(6) 配置文件App.config,在配置文件中存储了代理主题类类名。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="proxy" value="ProxySample.ProxySearcher"/>
</appSettings>
</configuration>
(7) Program:客户端测试类
- 结果及分析
在数据库中验证用户'杨过'是否是合法用户?
'杨过'登录成功!
用户'杨过'使用关键词'玉女心经'查询商务信息!
本实例是保护代理和智能引用代理的应用实例,在代理类ProxySearcher中实现对真实主题类的权限控制和引用计数,如果需要在访问真实主题时增加新的访问控制机制和新功能,只需增加一个新的代理类,再修改配置文件,在客户端代码中使用新增代理类即可,源代码无须修改,符合开闭原则。