代理模式(Proxy)

转载 https://blog.csdn.net/lovelion/article/details/8228042

某软件公司承接了某信息咨询公司的收费商务信息查询系统的开发任务,该系统的基本需求如下:

(1) 在进行商务信息查询之前用户需要通过身份验证,只有合法用户才能够使用该查询系统;

(2) 在进行商务信息查询时系统需要记录查询日志,以便根据查询次数收取查询费用。

该软件公司开发人员已完成了商务信息查询模块的开发任务,现希望能够以一种松耦合的方式向原有系统增加身份验证和日志记录功能,客户端代码可以无区别地对待原始的商务信息查询模块和增加新功能之后的商务信息查询模块,而且可能在将来还要在该信息查询模块中增加一些新的功能。

试使用代理模式设计并实现该收费商务信息查询系统。

  1. 实例分析及类图

通过分析,可以采用一种间接访问的方式来实现该商务信息查询系统的设计,在客户端对象和信息查询对象之间增加一个代理对象,让代理对象来实现身份验证和日志记录等功能,而无须直接对原有的商务信息查询对象进行修改,如图1-1所示:

1-1.png

在图中,客户端对象通过代理对象间接访问具有商务信息查询功能的真实对象,在代理对象中除了调用真实对象的商务信息查询功能外,还增加了身份验证和日志记录等功能。使用代理模式设计该商务信息查询系统,结构图如图1-2所示。

1-2.png

在图1-2中,业务类AccessValidator用于验证用户身份,业务类Logger用于记录用户查询日志,Searcher充当抽象主题角色,RealSearcher充当真实主题角色,ProxySearcher充当代理主题角色

  1. 实例代码 (1) AccessValidator:身份验证类,业务类,它提供方法Validate()来实现身份验证。
//AccessValidator.cs
using System;
 
namespace ProxySample
{
    class AccessValidator
    {
        //模拟实现登录验证
        public bool Validate(string userId) 
        {
            Console.WriteLine("在数据库中验证用户'" + userId + "'是否是合法用户?");
            if (userId.Equals("杨过")) {
                Console.WriteLine("'{0}'登录成功!",userId);
                return true;
            }
            else {
                Console.WriteLine("'{0}'登录失败!", userId);
                return false;
            }
        }
    }

(2) Logger:日志记录类,业务类,它提供方法Log()来保存日志。

//Logger.cs
using System;
 
namespace ProxySample
{
    class Logger
    {
        //模拟实现日志记录
        public void Log(string userId) {
            Console.WriteLine("更新数据库,用户'{0}'查询次数加1!",userId);
        }
    }
}

(3) Searcher:抽象查询类,充当抽象主题角色,它声明了DoSearch()方法。

namespace ProxySample
{
    interface Searcher
    {
        string DoSearch(string userId, string keyword);
    }
}

(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对象的引用。

namespace ProxySample
{
    class ProxySearcher : Searcher
    {
        private RealSearcher searcher = new RealSearcher(); //维持一个对真实主题的引用
        private AccessValidator validator;
        private Logger logger;
 
        public string DoSearch(string userId, string keyword)
        {
            //如果身份验证成功,则执行查询
            if (this.Validate(userId))
            {
                string result = searcher.DoSearch(userId, keyword); //调用真实主题对象的查询方法
                this.Log(userId); //记录查询日志
                return result; //返回查询结果
            }
            else
            {
                return null;
            }
        }
 
        //创建访问验证对象并调用其Validate()方法实现身份验证
        public bool Validate(string userId)
        {
            validator = new AccessValidator();
            return validator.Validate(userId);
        }
 
        //创建日志记录对象并调用其Log()方法实现日志记录
        public void Log(string userId)
        {
            logger = new Logger();
            logger.Log(userId);
        }
    }
}

(6) 配置文件App.config,在配置文件中存储了代理主题类类名。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="proxy" value="ProxySample.ProxySearcher"/>
  </appSettings>
</configuration>

(7) Program:客户端测试类

//Program.cs
using System;
using System.Configuration;
using System.Reflection;
 
namespace ProxySample
{
    class Program
    {
        static void Main(string[] args)
        {
            //读取配置文件
            string proxy = ConfigurationManager.AppSettings["proxy"];
 
            //反射生成对象,针对抽象编程,客户端无须分辨真实主题类和代理类
            Searcher searcher;
            searcher = (Searcher)Assembly.Load("ProxySample").CreateInstance(proxy);
 
            String result = searcher.DoSearch("杨过", "玉女心经");
            Console.Read();
        }
    }
}

结果及分析

在数据库中验证用户'杨过'是否是合法用户? '杨过'登录成功! 用户'杨过'使用关键词'玉女心经'查询商务信息! 更新数据库,用户'杨过'查询次数加1!

本实例是保护代理和智能引用代理的应用实例,在代理类ProxySearcher中实现对真实主题类的权限控制和引用计数,如果需要在访问真实主题时增加新的访问控制机制和新功能,只需增加一个新的代理类,再修改配置文件,在客户端代码中使用新增代理类即可,源代码无须修改,符合开闭原则。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏xingoo, 一个梦想做发明家的程序员

基于ELK的数据分析实践——满满的干货送给你

很多人刚刚接触ELK都不知道如何使用它们来做分析,经常会碰到下面的问题: 安装完ELK不知从哪下手 拿到数据样本不知道怎么分解数据 导入到elastics...

51070
来自专栏跟着阿笨一起玩NET

使用FileSystemWatcher监视文件变化

本文转载:http://www.cnblogs.com/zanxiaofeng/archive/2011/01/08/1930583.html

9610
来自专栏我的小碗汤

听说你还没掌握Normalizer的使用方法?

在 Elasticsearch 中处理字符串类型的数据时,如果我们想把整个字符串作为一个完整的 term 存储,我们通常会将其类型 type 设定为 keywo...

17740
来自专栏IT可乐

mybatis 详解(八)------ 懒加载

  本章我们讲如何通过懒加载来提高mybatis的查询效率。   本章所有代码:http://pan.baidu.com/s/1o8p2Drs 密码:trd6 ...

43290
来自专栏jiajia_deng

递归删除文件(支持通配符)

24440
来自专栏芋道源码1024

分布式事务 TCC-Transaction 源码解析 —— 事务存储器

本文主要基于 TCC-Transaction 1.2.3.3 正式版 1. 概述 2. 序列化 2.1 JDK 序列化实现 2.2 Kyro 序列化实现 2.3...

50360
来自专栏我的博客

TP入门第三天

1、系统常量 TP2.1版本:(蓝色是3.0中去掉) __ROOT__  : 网站根目录地址  __APP__  : 当前项目(入口文件)地址  __GROUP...

28750
来自专栏Venyo 的专栏

dotnet core 直接引用dll

dotnet core 只支持引用项目和nuget中的dll,外部dll虽然也可以引用进项目,并且可以被vs识别,而且编译后也可以在bin文件夹下看到对应的dl...

36850
来自专栏程序猿

SQL注入与XSS漏洞

所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求 的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如先前的很多影视网 站泄...

67650
来自专栏智能大石头

充血模型的ORM能做什么?——ORM组件XCode(十八般武艺)

ORM组件XCode(十八般武艺) 之前,XCode总是若隐若现,耐性好的同学想知道它还有啥特点,沉不住气的则认为不过是CURD耳! XCode开发模式是灵魂,...

20990

扫码关注云+社区

领取腾讯云代金券